From 7aa5f449edc8db7130b07fd9aa10502336197a06 Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Wed, 26 Jun 2024 23:31:27 +0900 Subject: [PATCH 1/7] feat: Create Profile Screen --- .../src/main/res/drawable/ic_write_line.xml | 14 ++ feature-main/main/build.gradle.kts | 2 +- .../com/apeun/gidaechi/main/MainScreen.kt | 6 +- feature-main/profile/.gitignore | 1 + feature-main/profile/build.gradle.kts | 13 ++ .../apeun/gidaechi/profile/ProfileScreen.kt | 183 ++++++++++++++++++ .../profile/navigation/ProfileNavigation.kt | 17 ++ settings.gradle.kts | 3 + 8 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 designsystem/src/main/res/drawable/ic_write_line.xml create mode 100644 feature-main/profile/.gitignore create mode 100644 feature-main/profile/build.gradle.kts create mode 100644 feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt create mode 100644 feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt diff --git a/designsystem/src/main/res/drawable/ic_write_line.xml b/designsystem/src/main/res/drawable/ic_write_line.xml new file mode 100644 index 00000000..1265e75c --- /dev/null +++ b/designsystem/src/main/res/drawable/ic_write_line.xml @@ -0,0 +1,14 @@ + + + + diff --git a/feature-main/main/build.gradle.kts b/feature-main/main/build.gradle.kts index 955d00cf..db48e52a 100644 --- a/feature-main/main/build.gradle.kts +++ b/feature-main/main/build.gradle.kts @@ -14,5 +14,5 @@ dependencies { implementation(projects.featureMain.home) implementation(projects.featureMain.room) implementation(projects.featureMain.roomCreate) - + implementation(projects.featureMain.profile) } \ No newline at end of file diff --git a/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt b/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt index f8784b58..b862d62c 100644 --- a/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt +++ b/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt @@ -26,6 +26,8 @@ import com.apeun.gidaechi.designsystem.component.BottomNavigationItemType import com.apeun.gidaechi.designsystem.component.SeugiBottomNavigation import com.apeun.gidaechi.home.navigation.HOME_ROUTE import com.apeun.gidaechi.home.navigation.homeScreen +import com.apeun.gidaechi.profile.navigation.PROFILE_ROUTE +import com.apeun.gidaechi.profile.navigation.profileScreen import com.apeun.gidaechi.room.navigation.ROOM_ROUTE import com.apeun.gidaechi.room.navigation.roomScreen import com.apeun.gidaechi.roomcreate.navigation.navigateToRoomCreate @@ -54,7 +56,7 @@ internal fun MainScreen(navHostController: NavHostController = rememberNavContro is BottomNavigationItemType.Chat -> CHAT_ROUTE is BottomNavigationItemType.Group -> ROOM_ROUTE is BottomNavigationItemType.Notification -> "route" - is BottomNavigationItemType.Profile -> "route" + is BottomNavigationItemType.Profile -> PROFILE_ROUTE else -> "route" }, ) { @@ -130,6 +132,8 @@ internal fun MainScreen(navHostController: NavHostController = rememberNavContro ) }, ) + + profileScreen() } } } diff --git a/feature-main/profile/.gitignore b/feature-main/profile/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature-main/profile/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature-main/profile/build.gradle.kts b/feature-main/profile/build.gradle.kts new file mode 100644 index 00000000..12dec288 --- /dev/null +++ b/feature-main/profile/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + alias(libs.plugins.seugi.android.feature) +} + +android { + namespace = "com.apeun.gidaechi.profile" +} + +dependencies { + + implementation(projects.designsystem) + implementation(projects.common) +} \ No newline at end of file diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt new file mode 100644 index 00000000..70d461d2 --- /dev/null +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt @@ -0,0 +1,183 @@ +package com.apeun.gidaechi.profile + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +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.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.apeun.gidaechi.designsystem.R.drawable +import com.apeun.gidaechi.designsystem.component.AvatarType +import com.apeun.gidaechi.designsystem.component.DividerType +import com.apeun.gidaechi.designsystem.component.SeugiAvatar +import com.apeun.gidaechi.designsystem.component.SeugiDivider +import com.apeun.gidaechi.designsystem.component.SeugiTopBar +import com.apeun.gidaechi.designsystem.theme.Black +import com.apeun.gidaechi.designsystem.theme.Gray500 +import com.apeun.gidaechi.designsystem.theme.White + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun ProfileScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .background(White) + ) { + SeugiTopBar( + title = { + Text( + text = "내 프로필", + style = MaterialTheme.typography.titleLarge, + color = Black + ) + } + ) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Spacer(modifier = Modifier.width(16.dp)) + SeugiAvatar(type = AvatarType.Medium) + Spacer(modifier = Modifier.width(10.dp)) + Text( + text = "노영재", + style = MaterialTheme.typography.titleMedium, + color = Black + ) + Spacer(modifier = Modifier.weight(1f)) + Image( + modifier = Modifier + .padding(vertical = 8.dp) + .size(32.dp), + painter = painterResource(id = drawable.ic_setting_fill), + contentDescription = "설정 톱니바퀴", + colorFilter = ColorFilter.tint(Gray500) + ) + Spacer(modifier = Modifier.width(16.dp)) + } + Spacer(modifier = Modifier.height(16.dp)) + SeugiDivider( + size = 8.dp, + type = DividerType.WIDTH + ) + + Spacer(modifier = Modifier.height(8.dp)) + ProfileCard( + title = "상태메세지", + content = "대소고 어딘가", + onClickEdit = {} + ) + Spacer(modifier = Modifier.height(8.dp)) + SeugiDivider( + modifier = Modifier.padding(horizontal = 16.dp), + type = DividerType.WIDTH, + ) + + Spacer(modifier = Modifier.height(8.dp)) + ProfileCard( + title = "직위", + content = "제갈 여친", + onClickEdit = {} + ) + Spacer(modifier = Modifier.height(8.dp)) + SeugiDivider( + modifier = Modifier.padding(horizontal = 16.dp), + type = DividerType.WIDTH, + ) + + Spacer(modifier = Modifier.height(8.dp)) + ProfileCard( + title = "소속", + content = "대소고 어딘가", + onClickEdit = {} + ) + Spacer(modifier = Modifier.height(8.dp)) + SeugiDivider( + modifier = Modifier.padding(horizontal = 16.dp), + type = DividerType.WIDTH, + ) + + Spacer(modifier = Modifier.height(8.dp)) + ProfileCard( + title = "휴대전화번호", + content = "010-1234-5678", + onClickEdit = {} + ) + Spacer(modifier = Modifier.height(8.dp)) + SeugiDivider( + modifier = Modifier.padding(horizontal = 16.dp), + type = DividerType.WIDTH, + ) + + Spacer(modifier = Modifier.height(8.dp)) + ProfileCard( + title = "유선전화번호", + content = "02-1234-5678", + onClickEdit = {} + ) + Spacer(modifier = Modifier.height(8.dp)) + SeugiDivider( + modifier = Modifier.padding(horizontal = 16.dp), + type = DividerType.WIDTH, + ) + + } +} + +@Composable +internal fun ProfileCard( + title: String, + content: String, + onClickEdit: () -> Unit, +) { + Column { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Spacer(modifier = Modifier.width(20.dp)) + Text( + text = title, + style = MaterialTheme.typography.bodyLarge, + color = Gray500 + ) + Spacer(modifier = Modifier.weight(1f)) + Image( + modifier = Modifier.size(20.dp), + painter = painterResource(id = drawable.ic_write_line), + contentDescription = "수정하기 아이콘", + colorFilter = ColorFilter.tint(Gray500) + ) + Spacer(modifier = Modifier.width(20.dp)) + } + Box( + modifier = Modifier + .fillMaxWidth() + .height(56.dp), + ) { + Text( + modifier = Modifier + .align(Alignment.CenterStart) + .padding(start = 20.dp), + text = content, + style = MaterialTheme.typography.titleMedium, + color = Black + ) + } + } +} \ No newline at end of file diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt new file mode 100644 index 00000000..dd4b683a --- /dev/null +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt @@ -0,0 +1,17 @@ +package com.apeun.gidaechi.profile.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.apeun.gidaechi.profile.ProfileScreen + +const val PROFILE_ROUTE = "profile" + +fun NavController.navigateToProfile(navOptions: NavOptions?) = navigate(PROFILE_ROUTE, navOptions) + +fun NavGraphBuilder.profileScreen() { + composable(PROFILE_ROUTE) { + ProfileScreen() + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 07778356..1fc6a7f3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,8 @@ import java.net.URI +include(":feature-main:profile") + + include(":data:group-chat") From 023d38c734c148daf6753f8ce71094427e9b84f7 Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Thu, 27 Jun 2024 08:38:30 +0900 Subject: [PATCH 2/7] feat: Create Profile Bottom Sheet --- .../apeun/gidaechi/profile/ProfileScreen.kt | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt index 70d461d2..f9d1fff4 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt @@ -9,31 +9,100 @@ 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.imePadding import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeGesturesPadding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.material.rememberBottomSheetState +import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.ModalBottomSheetProperties import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.apeun.gidaechi.designsystem.R.drawable +import com.apeun.gidaechi.designsystem.animation.bounceClick import com.apeun.gidaechi.designsystem.component.AvatarType +import com.apeun.gidaechi.designsystem.component.ButtonType import com.apeun.gidaechi.designsystem.component.DividerType import com.apeun.gidaechi.designsystem.component.SeugiAvatar import com.apeun.gidaechi.designsystem.component.SeugiDivider +import com.apeun.gidaechi.designsystem.component.SeugiFullWidthButton import com.apeun.gidaechi.designsystem.component.SeugiTopBar +import com.apeun.gidaechi.designsystem.component.textfield.SeugiTextField import com.apeun.gidaechi.designsystem.theme.Black import com.apeun.gidaechi.designsystem.theme.Gray500 import com.apeun.gidaechi.designsystem.theme.White +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun ProfileScreen() { + var isShowDialog by remember { mutableStateOf(false) } + val modalBottomSheetState = rememberModalBottomSheetState() + val coroutineScope = rememberCoroutineScope() + + val dialogDismissRequest: () -> Unit = { + coroutineScope.launch { + isShowDialog = false + } + } + + if (isShowDialog) { + ModalBottomSheet( + onDismissRequest = { dialogDismissRequest() }, + sheetState = modalBottomSheetState, + dragHandle = { BottomSheetDefaults.DragHandle() }, + containerColor = White, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .background(White) + .safeGesturesPadding(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = 20.dp + ) + ) { + Text( + text = "직위 수정", + style = MaterialTheme.typography.titleMedium, + color = Black + ) + Spacer(modifier = Modifier.height(4.dp)) + SeugiTextField(value = "qew", onValueChange = {}, onClickDelete = { /*TODO*/ }) + } + Spacer(modifier = Modifier.height(32.dp)) + SeugiFullWidthButton( + modifier = Modifier.padding(horizontal = 20.dp), + onClick = { dialogDismissRequest() }, + type = ButtonType.Primary, + text = "저장" + ) + Spacer(modifier = Modifier.imePadding()) + } + } + } + Column( modifier = Modifier .fillMaxSize() @@ -81,7 +150,9 @@ internal fun ProfileScreen() { ProfileCard( title = "상태메세지", content = "대소고 어딘가", - onClickEdit = {} + onClickEdit = { + isShowDialog = true + } ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -167,6 +238,9 @@ internal fun ProfileCard( } Box( modifier = Modifier + .bounceClick( + onClick = onClickEdit + ) .fillMaxWidth() .height(56.dp), ) { From 514034d2d5c8338a055c50f4af8f8562a4069156 Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Thu, 27 Jun 2024 13:48:10 +0900 Subject: [PATCH 3/7] feat: Create Profile Remote Load --- feature-main/profile/build.gradle.kts | 2 + .../apeun/gidaechi/profile/ProfileScreen.kt | 39 ++++++++++++----- .../gidaechi/profile/ProfileViewModel.kt | 42 +++++++++++++++++++ .../gidaechi/profile/model/ProfileUiState.kt | 18 ++++++++ 4 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt create mode 100644 feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt diff --git a/feature-main/profile/build.gradle.kts b/feature-main/profile/build.gradle.kts index 12dec288..0a9b669a 100644 --- a/feature-main/profile/build.gradle.kts +++ b/feature-main/profile/build.gradle.kts @@ -10,4 +10,6 @@ dependencies { implementation(projects.designsystem) implementation(projects.common) + implementation(projects.data.profile) + implementation(projects.data.core) } \ No newline at end of file diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt index f9d1fff4..3e3cc156 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeGesturesPadding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.material.rememberBottomSheetState import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme @@ -23,6 +22,7 @@ import androidx.compose.material3.ModalBottomSheetProperties import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -34,6 +34,8 @@ import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.apeun.gidaechi.designsystem.R.drawable import com.apeun.gidaechi.designsystem.animation.bounceClick import com.apeun.gidaechi.designsystem.component.AvatarType @@ -51,8 +53,14 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun ProfileScreen() { +internal fun ProfileScreen( + viewModel: ProfileViewModel = hiltViewModel(), +) { + val state by viewModel.state.collectAsStateWithLifecycle() + var isShowDialog by remember { mutableStateOf(false) } + var editTextTarget by remember { mutableStateOf("") } + var editText by remember { mutableStateOf("") } val modalBottomSheetState = rememberModalBottomSheetState() val coroutineScope = rememberCoroutineScope() @@ -62,6 +70,10 @@ internal fun ProfileScreen() { } } + LaunchedEffect(key1 = true) { + viewModel.load() + } + if (isShowDialog) { ModalBottomSheet( onDismissRequest = { dialogDismissRequest() }, @@ -84,12 +96,19 @@ internal fun ProfileScreen() { ) ) { Text( - text = "직위 수정", + text = "$editTextTarget 수정", style = MaterialTheme.typography.titleMedium, color = Black ) Spacer(modifier = Modifier.height(4.dp)) - SeugiTextField(value = "qew", onValueChange = {}, onClickDelete = { /*TODO*/ }) + + SeugiTextField( + value = editText, + onValueChange = { + editText = it + }, + onClickDelete = { /*TODO*/ } + ) } Spacer(modifier = Modifier.height(32.dp)) SeugiFullWidthButton( @@ -125,7 +144,7 @@ internal fun ProfileScreen() { SeugiAvatar(type = AvatarType.Medium) Spacer(modifier = Modifier.width(10.dp)) Text( - text = "노영재", + text = state.profileInfo.member.name, style = MaterialTheme.typography.titleMedium, color = Black ) @@ -149,7 +168,7 @@ internal fun ProfileScreen() { Spacer(modifier = Modifier.height(8.dp)) ProfileCard( title = "상태메세지", - content = "대소고 어딘가", + content = state.profileInfo.status, onClickEdit = { isShowDialog = true } @@ -163,7 +182,7 @@ internal fun ProfileScreen() { Spacer(modifier = Modifier.height(8.dp)) ProfileCard( title = "직위", - content = "제갈 여친", + content = state.profileInfo.spot, onClickEdit = {} ) Spacer(modifier = Modifier.height(8.dp)) @@ -175,7 +194,7 @@ internal fun ProfileScreen() { Spacer(modifier = Modifier.height(8.dp)) ProfileCard( title = "소속", - content = "대소고 어딘가", + content = state.profileInfo.belong, onClickEdit = {} ) Spacer(modifier = Modifier.height(8.dp)) @@ -187,7 +206,7 @@ internal fun ProfileScreen() { Spacer(modifier = Modifier.height(8.dp)) ProfileCard( title = "휴대전화번호", - content = "010-1234-5678", + content = state.profileInfo.phone, onClickEdit = {} ) Spacer(modifier = Modifier.height(8.dp)) @@ -199,7 +218,7 @@ internal fun ProfileScreen() { Spacer(modifier = Modifier.height(8.dp)) ProfileCard( title = "유선전화번호", - content = "02-1234-5678", + content = state.profileInfo.wire, onClickEdit = {} ) Spacer(modifier = Modifier.height(8.dp)) diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt new file mode 100644 index 00000000..1b7b28e9 --- /dev/null +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt @@ -0,0 +1,42 @@ +package com.apeun.gidaechi.profile + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.apeun.gidaechi.common.model.Result +import com.apeun.gidaechi.data.profile.ProfileRepository +import com.apeun.gidaechi.profile.model.ProfileUiState +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ProfileViewModel @Inject constructor( + private val profileRepository: ProfileRepository +): ViewModel() { + + private val _state = MutableStateFlow(ProfileUiState()) + val state = _state.asStateFlow() + + fun load() = viewModelScope.launch { + profileRepository.getProfile("664bdd0b9dfce726abd30462").collect { result -> + when(result) { + is Result.Success -> { + _state.update { + it.copy( + profileInfo = result.data + ) + } + } + is Result.Loading -> { + + } + is Result.Error -> { + result.throwable.printStackTrace() + } + } + } + } +} \ No newline at end of file diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt new file mode 100644 index 00000000..f776534f --- /dev/null +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt @@ -0,0 +1,18 @@ +package com.apeun.gidaechi.profile.model + +import com.apeun.gidaechi.data.core.model.ProfileModel +import com.apeun.gidaechi.data.core.model.UserModel + +data class ProfileUiState( + val profileInfo: ProfileModel = ProfileModel( + "", + UserModel(0, "", "", "", ""), + "", + "", + "", + "", + "", + "", + "" + ) +) \ No newline at end of file From e14faa20710e0e35711db10eb91f8d80430e08af Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Thu, 27 Jun 2024 14:08:51 +0900 Subject: [PATCH 4/7] feat: Create Profile Info Update Ui Logic --- .../apeun/gidaechi/profile/ProfileScreen.kt | 45 ++++++++++++++++--- .../gidaechi/profile/ProfileViewModel.kt | 21 +++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt index 3e3cc156..c69e79b0 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt @@ -96,7 +96,7 @@ internal fun ProfileScreen( ) ) { Text( - text = "$editTextTarget 수정", + text = "${getTargetTextToString(editTextTarget)} 수정", style = MaterialTheme.typography.titleMedium, color = Black ) @@ -113,7 +113,15 @@ internal fun ProfileScreen( Spacer(modifier = Modifier.height(32.dp)) SeugiFullWidthButton( modifier = Modifier.padding(horizontal = 20.dp), - onClick = { dialogDismissRequest() }, + onClick = { + viewModel.updateState( + target = editTextTarget, + text = editText + ) + editText = "" + editTextTarget = "" + dialogDismissRequest() + }, type = ButtonType.Primary, text = "저장" ) @@ -170,6 +178,7 @@ internal fun ProfileScreen( title = "상태메세지", content = state.profileInfo.status, onClickEdit = { + editTextTarget = "status" isShowDialog = true } ) @@ -183,7 +192,10 @@ internal fun ProfileScreen( ProfileCard( title = "직위", content = state.profileInfo.spot, - onClickEdit = {} + onClickEdit = { + editTextTarget = "spot" + isShowDialog = true + } ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -195,7 +207,10 @@ internal fun ProfileScreen( ProfileCard( title = "소속", content = state.profileInfo.belong, - onClickEdit = {} + onClickEdit = { + editTextTarget = "belong" + isShowDialog = true + } ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -207,7 +222,10 @@ internal fun ProfileScreen( ProfileCard( title = "휴대전화번호", content = state.profileInfo.phone, - onClickEdit = {} + onClickEdit = { + editTextTarget = "phone" + isShowDialog = true + } ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -219,7 +237,10 @@ internal fun ProfileScreen( ProfileCard( title = "유선전화번호", content = state.profileInfo.wire, - onClickEdit = {} + onClickEdit = { + editTextTarget = "wire" + isShowDialog = true + } ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -273,4 +294,14 @@ internal fun ProfileCard( ) } } -} \ No newline at end of file +} + +private fun getTargetTextToString(text: String) = + when(text) { + "status" -> "상태메세지" + "spot" -> "직위" + "belong" -> "소속" + "phone" -> "휴대전화번호" + "wire" -> "유선전화번호" + else -> "" + } \ No newline at end of file diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt index 1b7b28e9..c437206a 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt @@ -39,4 +39,25 @@ class ProfileViewModel @Inject constructor( } } } + + fun updateState(target: String, text: String) { + val info = _state.value.profileInfo + with(info) { + _state.update { + it.copy( + profileInfo = info.copy( + status = if (target == "status") text else status, + member = member, + workspaceId = workspaceId, + nick = if (target == "nick") text else nick, + spot = if (target == "spot") text else spot, + belong = if (target == "belong") text else belong, + phone = if (target == "phone") text else phone, + wire = if (target == "wire") text else wire, + location = location + ) + ) + } + } + } } \ No newline at end of file From 1215022fea479f767d992d235a7f5f1c1e05296f Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Thu, 27 Jun 2024 15:08:42 +0900 Subject: [PATCH 5/7] feat: Create Profile Bottom Sheet Placeholder --- .../apeun/gidaechi/profile/ProfileScreen.kt | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt index c69e79b0..7d234aff 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -61,6 +62,7 @@ internal fun ProfileScreen( var isShowDialog by remember { mutableStateOf(false) } var editTextTarget by remember { mutableStateOf("") } var editText by remember { mutableStateOf("") } + val editTextString by remember { derivedStateOf { getTargetTextToString(editTextTarget) } } val modalBottomSheetState = rememberModalBottomSheetState() val coroutineScope = rememberCoroutineScope() @@ -96,7 +98,7 @@ internal fun ProfileScreen( ) ) { Text( - text = "${getTargetTextToString(editTextTarget)} 수정", + text = "${editTextString.first} 수정", style = MaterialTheme.typography.titleMedium, color = Black ) @@ -107,7 +109,10 @@ internal fun ProfileScreen( onValueChange = { editText = it }, - onClickDelete = { /*TODO*/ } + placeholder = "${editTextString.first}${editTextString.second} 입력해주세요", + onClickDelete = { + editText = "" + } ) } Spacer(modifier = Modifier.height(32.dp)) @@ -296,12 +301,12 @@ internal fun ProfileCard( } } -private fun getTargetTextToString(text: String) = +private fun getTargetTextToString(text: String): Pair = when(text) { - "status" -> "상태메세지" - "spot" -> "직위" - "belong" -> "소속" - "phone" -> "휴대전화번호" - "wire" -> "유선전화번호" - else -> "" + "status" -> Pair("상태메세지", "를") + "spot" -> Pair("직위", "를") + "belong" -> Pair("소속", "을") + "phone" -> Pair("휴대전화번호", "를") + "wire" -> Pair("유선전화번호", "를") + else -> Pair("", "") } \ No newline at end of file From 6337e86a1c56c1545aee7206cd545d68aba2b859 Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Thu, 27 Jun 2024 15:10:10 +0900 Subject: [PATCH 6/7] style: Apply Spotless Format --- .../apeun/gidaechi/profile/ProfileScreen.kt | 78 ++++++++----------- .../gidaechi/profile/ProfileViewModel.kt | 17 ++-- .../gidaechi/profile/model/ProfileUiState.kt | 6 +- .../profile/navigation/ProfileNavigation.kt | 2 +- 4 files changed, 46 insertions(+), 57 deletions(-) diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt index 7d234aff..2ed0bf62 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileScreen.kt @@ -18,7 +18,6 @@ import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.ModalBottomSheetProperties import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -33,7 +32,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -54,9 +52,7 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun ProfileScreen( - viewModel: ProfileViewModel = hiltViewModel(), -) { +internal fun ProfileScreen(viewModel: ProfileViewModel = hiltViewModel()) { val state by viewModel.state.collectAsStateWithLifecycle() var isShowDialog by remember { mutableStateOf(false) } @@ -88,19 +84,19 @@ internal fun ProfileScreen( .fillMaxWidth() .background(White) .safeGesturesPadding(), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, ) { Column( modifier = Modifier .fillMaxWidth() .padding( - horizontal = 20.dp - ) + horizontal = 20.dp, + ), ) { Text( text = "${editTextString.first} 수정", style = MaterialTheme.typography.titleMedium, - color = Black + color = Black, ) Spacer(modifier = Modifier.height(4.dp)) @@ -112,7 +108,7 @@ internal fun ProfileScreen( placeholder = "${editTextString.first}${editTextString.second} 입력해주세요", onClickDelete = { editText = "" - } + }, ) } Spacer(modifier = Modifier.height(32.dp)) @@ -121,14 +117,14 @@ internal fun ProfileScreen( onClick = { viewModel.updateState( target = editTextTarget, - text = editText + text = editText, ) editText = "" editTextTarget = "" dialogDismissRequest() }, type = ButtonType.Primary, - text = "저장" + text = "저장", ) Spacer(modifier = Modifier.imePadding()) } @@ -138,20 +134,20 @@ internal fun ProfileScreen( Column( modifier = Modifier .fillMaxSize() - .background(White) + .background(White), ) { SeugiTopBar( title = { Text( text = "내 프로필", style = MaterialTheme.typography.titleLarge, - color = Black + color = Black, ) - } + }, ) Row( modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, ) { Spacer(modifier = Modifier.width(16.dp)) SeugiAvatar(type = AvatarType.Medium) @@ -159,7 +155,7 @@ internal fun ProfileScreen( Text( text = state.profileInfo.member.name, style = MaterialTheme.typography.titleMedium, - color = Black + color = Black, ) Spacer(modifier = Modifier.weight(1f)) Image( @@ -168,14 +164,14 @@ internal fun ProfileScreen( .size(32.dp), painter = painterResource(id = drawable.ic_setting_fill), contentDescription = "설정 톱니바퀴", - colorFilter = ColorFilter.tint(Gray500) + colorFilter = ColorFilter.tint(Gray500), ) Spacer(modifier = Modifier.width(16.dp)) } Spacer(modifier = Modifier.height(16.dp)) SeugiDivider( size = 8.dp, - type = DividerType.WIDTH + type = DividerType.WIDTH, ) Spacer(modifier = Modifier.height(8.dp)) @@ -185,7 +181,7 @@ internal fun ProfileScreen( onClickEdit = { editTextTarget = "status" isShowDialog = true - } + }, ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -200,7 +196,7 @@ internal fun ProfileScreen( onClickEdit = { editTextTarget = "spot" isShowDialog = true - } + }, ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -215,7 +211,7 @@ internal fun ProfileScreen( onClickEdit = { editTextTarget = "belong" isShowDialog = true - } + }, ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -230,7 +226,7 @@ internal fun ProfileScreen( onClickEdit = { editTextTarget = "phone" isShowDialog = true - } + }, ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( @@ -245,46 +241,41 @@ internal fun ProfileScreen( onClickEdit = { editTextTarget = "wire" isShowDialog = true - } + }, ) Spacer(modifier = Modifier.height(8.dp)) SeugiDivider( modifier = Modifier.padding(horizontal = 16.dp), type = DividerType.WIDTH, ) - } } @Composable -internal fun ProfileCard( - title: String, - content: String, - onClickEdit: () -> Unit, -) { +internal fun ProfileCard(title: String, content: String, onClickEdit: () -> Unit) { Column { Row( - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, ) { Spacer(modifier = Modifier.width(20.dp)) Text( text = title, style = MaterialTheme.typography.bodyLarge, - color = Gray500 + color = Gray500, ) Spacer(modifier = Modifier.weight(1f)) Image( modifier = Modifier.size(20.dp), painter = painterResource(id = drawable.ic_write_line), contentDescription = "수정하기 아이콘", - colorFilter = ColorFilter.tint(Gray500) + colorFilter = ColorFilter.tint(Gray500), ) Spacer(modifier = Modifier.width(20.dp)) } Box( modifier = Modifier .bounceClick( - onClick = onClickEdit + onClick = onClickEdit, ) .fillMaxWidth() .height(56.dp), @@ -295,18 +286,17 @@ internal fun ProfileCard( .padding(start = 20.dp), text = content, style = MaterialTheme.typography.titleMedium, - color = Black + color = Black, ) } } } -private fun getTargetTextToString(text: String): Pair = - when(text) { - "status" -> Pair("상태메세지", "를") - "spot" -> Pair("직위", "를") - "belong" -> Pair("소속", "을") - "phone" -> Pair("휴대전화번호", "를") - "wire" -> Pair("유선전화번호", "를") - else -> Pair("", "") - } \ No newline at end of file +private fun getTargetTextToString(text: String): Pair = when (text) { + "status" -> Pair("상태메세지", "를") + "spot" -> Pair("직위", "를") + "belong" -> Pair("소속", "을") + "phone" -> Pair("휴대전화번호", "를") + "wire" -> Pair("유선전화번호", "를") + else -> Pair("", "") +} diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt index c437206a..846f405c 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/ProfileViewModel.kt @@ -6,32 +6,31 @@ import com.apeun.gidaechi.common.model.Result import com.apeun.gidaechi.data.profile.ProfileRepository import com.apeun.gidaechi.profile.model.ProfileUiState import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import javax.inject.Inject @HiltViewModel class ProfileViewModel @Inject constructor( - private val profileRepository: ProfileRepository -): ViewModel() { + private val profileRepository: ProfileRepository, +) : ViewModel() { private val _state = MutableStateFlow(ProfileUiState()) val state = _state.asStateFlow() fun load() = viewModelScope.launch { profileRepository.getProfile("664bdd0b9dfce726abd30462").collect { result -> - when(result) { + when (result) { is Result.Success -> { _state.update { it.copy( - profileInfo = result.data + profileInfo = result.data, ) } } is Result.Loading -> { - } is Result.Error -> { result.throwable.printStackTrace() @@ -54,10 +53,10 @@ class ProfileViewModel @Inject constructor( belong = if (target == "belong") text else belong, phone = if (target == "phone") text else phone, wire = if (target == "wire") text else wire, - location = location - ) + location = location, + ), ) } } } -} \ No newline at end of file +} diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt index f776534f..d2f6b7d7 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/model/ProfileUiState.kt @@ -13,6 +13,6 @@ data class ProfileUiState( "", "", "", - "" - ) -) \ No newline at end of file + "", + ), +) diff --git a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt index dd4b683a..83cab4c4 100644 --- a/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt +++ b/feature-main/profile/src/main/java/com/apeun/gidaechi/profile/navigation/ProfileNavigation.kt @@ -14,4 +14,4 @@ fun NavGraphBuilder.profileScreen() { composable(PROFILE_ROUTE) { ProfileScreen() } -} \ No newline at end of file +} From c443cf5bfeb612a675465aa9153bb8f53938a10c Mon Sep 17 00:00:00 2001 From: 8954sood <8954sood@naver.com> Date: Thu, 27 Jun 2024 15:36:03 +0900 Subject: [PATCH 7/7] chore: Recovery On Merge Delete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 머지가 되면서 사라진 것을 복구하였습니다. --- .../main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt b/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt index c3ffe65c..f3cc04cc 100644 --- a/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt +++ b/feature-main/main/src/main/java/com/apeun/gidaechi/main/MainScreen.kt @@ -57,8 +57,8 @@ internal fun MainScreen(navHostController: NavHostController = rememberNavContro is BottomNavigationItemType.Home -> HOME_ROUTE is BottomNavigationItemType.Chat -> CHAT_ROUTE is BottomNavigationItemType.Group -> ROOM_ROUTE - is BottomNavigationItemType.Notification -> "route" - is BottomNavigationItemType.Profile -> "route" + is BottomNavigationItemType.Notification -> NOTIFICATION_ROUTE + is BottomNavigationItemType.Profile -> PROFILE_ROUTE else -> "route" }, ) {