Skip to content

Commit

Permalink
Merge pull request #103 from Mnseo/feature/101_profile
Browse files Browse the repository at this point in the history
  • Loading branch information
Mnseo authored Feb 8, 2024
2 parents e76ec04 + 68a506d commit b67045f
Show file tree
Hide file tree
Showing 15 changed files with 1,508 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -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())
}
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.kusitms.presentation.model.profile.edit

data class ProfileEditUiState(
val currentSelectedProfileFilter: String = "기본 프로필",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
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
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject

@HiltViewModel
class ProfileEditViewModel @Inject constructor(

) : ViewModel() {
private val _uiState = MutableStateFlow(ProfileEditUiState())
val uiState: StateFlow<ProfileEditUiState> = _uiState.asStateFlow()

private val _isAllFieldsValid = MutableStateFlow(false)
val isAllFieldsValid: StateFlow<Boolean> = _isAllFieldsValid

private val _expanded = MutableStateFlow(false)
val expended: StateFlow<Boolean> = _expanded.asStateFlow()

private val _favoriteCategory = MutableStateFlow<List<String>?>(null)
val favoriteCategory: StateFlow<List<String>?> = _favoriteCategory

private val _interests = MutableStateFlow<List<InterestItem>>(emptyList())
val interests: StateFlow<List<InterestItem>> = _interests.asStateFlow()

private val _name = MutableStateFlow("")
val name: StateFlow<String> = _name

private val _major = MutableStateFlow("")
val major: StateFlow<String> = _major

private val _phoneNum = MutableStateFlow("")
val phoneNum: StateFlow<String> = _phoneNum

private val _email = MutableStateFlow("")
val email: StateFlow<String> = _email

private val _emailError = MutableStateFlow<String?>(null)
val emailError: StateFlow<String?> = _emailError

private val _phoneNumError = MutableStateFlow<String?>(null)
val phoneNumError: StateFlow<String?> = _phoneNumError


private val _selectedImage = MutableStateFlow<Uri?>(null)
val selectedImage: StateFlow<Uri?> = _selectedImage.asStateFlow()

private val _linkItems = MutableStateFlow<List<LinkItem>>(listOf(LinkItem(LinkType.LINK, "")))
val linkItems: StateFlow<List<LinkItem>> = _linkItems.asStateFlow()

private val _introduce = MutableStateFlow("")
val introduce: StateFlow<String> = _introduce

private val _signInStatus = MutableStateFlow(SignInStatus.DEFAULT)
val signInStatus : StateFlow<SignInStatus> = _signInStatus

private val _selectedPart = MutableStateFlow<String?>(null)
val selectedPart: StateFlow<String?> = _selectedPart

fun changeSelectProfileFilter(category: String) {
_uiState.value = _uiState.value.copy(currentSelectedProfileFilter = category)
_expanded.value = false
}

fun toggleExpanded() {
_expanded.value = !_expanded.value
}

fun updateMajor(newMajor: String) {
_major.value = newMajor
validateFields()
}


fun updateSelectedPart(part: String) {
_selectedPart.value = part
validateFields()
}

fun updateInterests(interestItems: List<InterestItem>) {
_interests.value = interestItems
validateFields()
}

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()
}

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
}


private fun validateFields() {
_isAllFieldsValid.value = _major.value.isNotBlank() &&
_selectedPart.value != null &&
_interests.value.isNotEmpty() &&
_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)
}

}
Original file line number Diff line number Diff line change
@@ -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 = "추가 프로필"),
)
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -62,6 +61,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
Expand Down Expand Up @@ -271,7 +271,10 @@ fun MainNavigation() {
arguments = NavRoutes.MyProfileDetail.navArguments
) {
MyProfileScreen(
onBack = { navController.navigateUp() }
onBack = { navController.navigateUp() },
onClickModify = {
navController.navigate(NavRoutes.ProfileEdit.route)
}
)
}

Expand Down Expand Up @@ -362,7 +365,10 @@ fun MainNavigation() {
arguments = NavRoutes.ProfileDetail.navArguments
) {
ProfileDetailScreen(
onBack = { navController.navigateUp() }
onBack = { navController.navigateUp() },
onClickModify = {
navController.navigate(NavRoutes.ProfileEdit.route)
}
)
}

Expand All @@ -381,6 +387,11 @@ fun MainNavigation() {
)
}

kusitmsComposableWithAnimation(NavRoutes.ProfileEdit.route) {
ProfileEditScreen(
onBack = { navController.navigateUp() }
)
}


kusitmsComposableWithAnimation(NavRoutes.ImageViewer.route) {
Expand Down
Loading

0 comments on commit b67045f

Please sign in to comment.