Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/Profile Screen #130

Merged
merged 8 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions designsystem/src/main/res/drawable/ic_write_line.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M18.356,2.438C18.888,2.174 19.512,2.174 20.044,2.438C20.329,2.579 20.57,2.821 20.778,3.031L20.895,3.148C21.104,3.356 21.347,3.596 21.488,3.882C21.751,4.414 21.751,5.038 21.488,5.569C21.346,5.855 21.104,6.096 20.895,6.304L11.073,16.126H7.8V12.853L17.622,3.031C17.83,2.821 18.071,2.579 18.356,2.438ZM19.271,4.069C19.232,4.03 19.168,4.03 19.129,4.069L9.6,13.598V14.325H10.327L19.856,4.796C19.895,4.757 19.895,4.694 19.856,4.655L19.271,4.069Z"
android:fillColor="#141415"
android:fillType="evenOdd"/>
<path
android:pathData="M7.163,2.826C6.494,2.826 5.938,2.826 5.485,2.863C5.012,2.902 4.572,2.985 4.156,3.197C3.517,3.522 2.997,4.043 2.671,4.682C2.459,5.098 2.376,5.538 2.337,6.011C2.3,6.464 2.3,7.02 2.3,7.689V16.763C2.3,17.431 2.3,17.987 2.337,18.441C2.376,18.914 2.459,19.354 2.671,19.77C2.997,20.409 3.517,20.929 4.156,21.255C4.572,21.467 5.012,21.55 5.485,21.589C5.938,21.626 6.494,21.626 7.163,21.626H16.237C16.906,21.626 17.462,21.626 17.915,21.589C18.388,21.55 18.828,21.467 19.244,21.255C19.883,20.929 20.404,20.409 20.729,19.77C20.941,19.354 21.024,18.914 21.063,18.441C21.1,17.987 21.1,17.431 21.1,16.763L21.1,11.226L19.3,11.226L19.3,16.726C19.3,17.441 19.299,17.923 19.269,18.295C19.24,18.656 19.187,18.833 19.126,18.952C18.972,19.253 18.728,19.498 18.427,19.652C18.307,19.712 18.13,19.765 17.769,19.795C17.397,19.825 16.915,19.826 16.2,19.826H7.2C6.485,19.826 6.003,19.825 5.631,19.795C5.27,19.765 5.093,19.712 4.974,19.652C4.673,19.498 4.428,19.253 4.274,18.952C4.214,18.833 4.161,18.656 4.131,18.295C4.101,17.923 4.1,17.441 4.1,16.726V7.726C4.1,7.011 4.101,6.529 4.131,6.157C4.161,5.796 4.214,5.619 4.274,5.5C4.428,5.198 4.673,4.954 4.974,4.8C5.093,4.74 5.27,4.687 5.631,4.657C6.003,4.627 6.485,4.626 7.2,4.626H12.7V2.826L7.163,2.826Z"
android:fillColor="#141415"
android:fillType="evenOdd"/>
</vector>
2 changes: 1 addition & 1 deletion feature-main/main/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ dependencies {
implementation(projects.featureMain.home)
implementation(projects.featureMain.room)
implementation(projects.featureMain.roomCreate)

implementation(projects.featureMain.profile)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
},
) {
Expand Down Expand Up @@ -130,6 +132,8 @@ internal fun MainScreen(navHostController: NavHostController = rememberNavContro
)
},
)

profileScreen()
}
}
}
1 change: 1 addition & 0 deletions feature-main/profile/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
15 changes: 15 additions & 0 deletions feature-main/profile/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
alias(libs.plugins.seugi.android.feature)
}

android {
namespace = "com.apeun.gidaechi.profile"
}

dependencies {

implementation(projects.designsystem)
implementation(projects.common)
implementation(projects.data.profile)
implementation(projects.data.core)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
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.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.material3.BottomSheetDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
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
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.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
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(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 editTextString by remember { derivedStateOf { getTargetTextToString(editTextTarget) } }
val modalBottomSheetState = rememberModalBottomSheetState()
val coroutineScope = rememberCoroutineScope()

val dialogDismissRequest: () -> Unit = {
coroutineScope.launch {
isShowDialog = false
}
}

LaunchedEffect(key1 = true) {
viewModel.load()
}

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 = "${editTextString.first} 수정",
style = MaterialTheme.typography.titleMedium,
color = Black,
)
Spacer(modifier = Modifier.height(4.dp))

SeugiTextField(
value = editText,
onValueChange = {
editText = it
},
placeholder = "${editTextString.first}${editTextString.second} 입력해주세요",
onClickDelete = {
editText = ""
},
)
}
Spacer(modifier = Modifier.height(32.dp))
SeugiFullWidthButton(
modifier = Modifier.padding(horizontal = 20.dp),
onClick = {
viewModel.updateState(
target = editTextTarget,
text = editText,
)
editText = ""
editTextTarget = ""
dialogDismissRequest()
},
type = ButtonType.Primary,
text = "저장",
)
Spacer(modifier = Modifier.imePadding())
}
}
}

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 = state.profileInfo.member.name,
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 = state.profileInfo.status,
onClickEdit = {
editTextTarget = "status"
isShowDialog = true
},
)
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 = state.profileInfo.spot,
onClickEdit = {
editTextTarget = "spot"
isShowDialog = true
},
)
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 = state.profileInfo.belong,
onClickEdit = {
editTextTarget = "belong"
isShowDialog = true
},
)
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 = state.profileInfo.phone,
onClickEdit = {
editTextTarget = "phone"
isShowDialog = true
},
)
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 = state.profileInfo.wire,
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) {
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
.bounceClick(
onClick = onClickEdit,
)
.fillMaxWidth()
.height(56.dp),
) {
Text(
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 20.dp),
text = content,
style = MaterialTheme.typography.titleMedium,
color = Black,
)
}
}
}

private fun getTargetTextToString(text: String): Pair<String, String> = when (text) {
"status" -> Pair("상태메세지", "를")
"spot" -> Pair("직위", "를")
"belong" -> Pair("소속", "을")
"phone" -> Pair("휴대전화번호", "를")
"wire" -> Pair("유선전화번호", "를")
else -> Pair("", "")
}
Loading
Loading