From 5b80e55940fa5a2ccb5db525d3a51544fc0227f9 Mon Sep 17 00:00:00 2001 From: eshc123 <> Date: Thu, 22 Aug 2024 20:53:05 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=ED=83=80=EC=9D=B4=ED=8B=80=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mission_mate/feature/board/component/BoardTopView.kt | 4 ++-- .../onboarding/screen/boardsetup/BoardSetupSuccessScreen.kt | 2 +- .../goalpanzi/mission_mate/feature/profile/ProfileScreen.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/component/BoardTopView.kt b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/component/BoardTopView.kt index d177c45f..038b3c73 100644 --- a/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/component/BoardTopView.kt +++ b/feature/board/src/main/java/com/goalpanzi/mission_mate/feature/board/component/BoardTopView.kt @@ -92,7 +92,7 @@ fun BoardTopView( indication = null, onClick = onClickTooltip ) - .padding(end = 43.dp,top = 48.dp) + .padding(end = 43.dp,top = 56.dp) .width(161.dp), drawableResId = R.drawable.img_tooltip_mission_invitation_code, contentScale = ContentScale.Crop @@ -106,7 +106,7 @@ fun BoardTopView( indication = null, onClick = onClickTooltip ) - .padding(start = 8.dp, top = 48.dp) + .padding(start = 8.dp, top = 56.dp) .width(161.dp), drawableResId = R.drawable.img_tooltip_mission_detail, contentScale = ContentScale.Crop diff --git a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/screen/boardsetup/BoardSetupSuccessScreen.kt b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/screen/boardsetup/BoardSetupSuccessScreen.kt index 3f92b054..046fd61d 100644 --- a/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/screen/boardsetup/BoardSetupSuccessScreen.kt +++ b/feature/onboarding/src/main/java/com/goalpanzi/mission_mate/feature/onboarding/screen/boardsetup/BoardSetupSuccessScreen.kt @@ -59,7 +59,7 @@ fun BoardSetupSuccessScreen( Text( modifier = Modifier .statusBarsPadding() - .padding(top = 48.dp, bottom = 52.dp), + .padding(top = 56.dp, bottom = 52.dp), text = stringResource(id = R.string.onboarding_board_setup_success_title), style = MissionMateTypography.heading_sm_bold, color = ColorGray1_FF404249, diff --git a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt index d6a3215f..322adf25 100644 --- a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt @@ -216,7 +216,7 @@ fun ColumnScope.ProfileScreen( ), modifier = modifier .align(Alignment.CenterHorizontally) - .padding(top = 48.dp), + .padding(top = if(profileSettingType == ProfileSettingType.SETTING) 0.dp else 56.dp), style = MissionMateTypography.heading_sm_bold, color = ColorGray1_FF404249 ) From 23ee7b961f76b1f5134bfe4c90c23de719a78508 Mon Sep 17 00:00:00 2001 From: eshc123 <> Date: Thu, 22 Aug 2024 21:16:42 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/profile/ProfileScreen.kt | 41 ++++++++++++------- .../feature/profile/ProfileViewModel.kt | 11 +++++ 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt index 322adf25..22fc8074 100644 --- a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt @@ -125,6 +125,7 @@ fun ProfileRoute( uiState = uiState, profileSettingType = profileSettingType, isNotChangedProfileInput = isNotChangedProfileInput, + nickname = viewModel.nickname, onClickCharacter = { viewModel.selectCharacter(it) }, onClickSave = { keyboardController?.hide() @@ -132,7 +133,8 @@ fun ProfileRoute( }, onBackClick = onBackClick, isInvalidNickname = isInvalidNickname, - resetNicknameErrorState = { viewModel.resetNicknameErrorState() } + resetNicknameErrorState = { viewModel.resetNicknameErrorState() }, + onNicknameChanged = viewModel::updateNickname ) } } @@ -143,10 +145,12 @@ fun ProfileContent( uiState: ProfileUiState, profileSettingType: ProfileSettingType, isNotChangedProfileInput: Boolean, + nickname : String, onClickCharacter: (CharacterListItem) -> Unit = {}, onClickSave: (String) -> Unit = {}, onBackClick: (() -> Unit)? = null, isInvalidNickname: Boolean, + onNicknameChanged : (String) -> Unit, resetNicknameErrorState: () -> Unit ) { Column( @@ -172,11 +176,13 @@ fun ProfileContent( profileSettingType = profileSettingType, initialNickname = uiState.nickname, characters = uiState.characterList, + nickname = nickname, isNotChangedProfileInput = isNotChangedProfileInput, onClickCharacter = onClickCharacter, onClickSave = onClickSave, isInvalidNickname = isInvalidNickname, - resetNicknameErrorState = resetNicknameErrorState + resetNicknameErrorState = resetNicknameErrorState, + onNicknameChanged = onNicknameChanged ) } } @@ -190,12 +196,14 @@ fun ColumnScope.ProfileScreen( profileSettingType: ProfileSettingType, characters: List, isNotChangedProfileInput: Boolean, + nickname : String, onClickCharacter: (CharacterListItem) -> Unit, onClickSave: (String) -> Unit, isInvalidNickname: Boolean, + onNicknameChanged : (String) -> Unit, resetNicknameErrorState: () -> Unit = {} ) { - var nicknameInput by remember { mutableStateOf(initialNickname) } + // var nicknameInput by remember { mutableStateOf(initialNickname) } val scrollState = rememberScrollState() val regex = Regex("^[가-힣ㅏ-ㅣㄱ-ㅎa-zA-Z0-9]{1,6}$") @@ -244,13 +252,14 @@ fun ColumnScope.ProfileScreen( .padding(top = 38.dp, start = 24.dp, end = 24.dp) .fillMaxWidth() .wrapContentHeight(), - text = nicknameInput, - onValueChange = { - if (regex.matches(it) || it.isEmpty()) { - nicknameInput = it - } - resetNicknameErrorState() - }, + text = nickname, + onValueChange = onNicknameChanged, +// { +// if (regex.matches(it) || it.isEmpty()) { +// nicknameInput = it +// } +// resetNicknameErrorState() +// }, hintId = R.string.nickname_hint, guidanceId = if (isInvalidNickname) R.string.err_duplicated_nickname else R.string.nickname_input_guide, isError = isInvalidNickname @@ -264,21 +273,21 @@ fun ColumnScope.ProfileScreen( textId = R.string.save, buttonType = if (profileSettingType == ProfileSettingType.CREATE) { - if (nicknameInput.trim().isEmpty()) { + if (nickname.trim().isEmpty()) { MissionMateButtonType.DISABLED } else { MissionMateButtonType.ACTIVE } } else { - if ((initialNickname == nicknameInput && isNotChangedProfileInput) || - nicknameInput.trim().isEmpty() + if ((initialNickname == nickname && isNotChangedProfileInput) || + nickname.trim().isEmpty() ) { MissionMateButtonType.DISABLED } else { MissionMateButtonType.ACTIVE } }, - onClick = { onClickSave(nicknameInput) } + onClick = { onClickSave(nickname) } ) } @@ -407,10 +416,12 @@ fun ColumnScope.ProfileScreenPreview() { backgroundResId = com.goalpanzi.mission_mate.core.designsystem.R.drawable.background_panda ), ), + nickname = "미션메이트", onClickCharacter = {}, onClickSave = {}, isInvalidNickname = false, - isNotChangedProfileInput = false + isNotChangedProfileInput = false, + onNicknameChanged = {} ) } diff --git a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt index 782b6712..a79cd362 100644 --- a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt @@ -1,5 +1,8 @@ package com.goalpanzi.mission_mate.feature.profile +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope @@ -43,6 +46,9 @@ class ProfileViewModel @AssistedInject constructor( private val defaultCharacters = CharacterListItem.createDefaultList() + var nickname by mutableStateOf("") + private set + private val _uiState = MutableStateFlow(ProfileUiState.Loading) val uiState = _uiState.asStateFlow() @@ -87,6 +93,11 @@ class ProfileViewModel @AssistedInject constructor( } } + fun updateNickname(input: String) { + nickname = input + + } + fun selectCharacter(character: CharacterListItem) { val state = uiState.value as? ProfileUiState.Success ?: return _uiState.value = state.copy( From 4d60b41716f7952631b09193847e62a26480c6f0 Mon Sep 17 00:00:00 2001 From: Changyeop Lee Date: Thu, 22 Aug 2024 21:54:04 +0900 Subject: [PATCH 3/3] Fix nickname text field error ui. --- .../feature/profile/ProfileScreen.kt | 82 ++++++++----------- .../feature/profile/ProfileViewModel.kt | 38 +++++---- 2 files changed, 57 insertions(+), 63 deletions(-) diff --git a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt index 22fc8074..f58d8c87 100644 --- a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt +++ b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileScreen.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel +import com.goalpanzi.core.model.CharacterType import com.goalpanzi.mission_mate.core.designsystem.component.MissionMateButtonType import com.goalpanzi.mission_mate.core.designsystem.component.MissionMateTextButton import com.goalpanzi.mission_mate.core.designsystem.component.MissionMateTextFieldGroup @@ -59,12 +60,10 @@ import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography import com.goalpanzi.mission_mate.core.designsystem.theme.component.MissionMateTopAppBar import com.goalpanzi.mission_mate.core.designsystem.theme.component.NavigationType -import com.goalpanzi.core.model.CharacterType import com.goalpanzi.mission_mate.feature.profile.model.CharacterListItem import com.goalpanzi.mission_mate.feature.profile.model.ProfileUiState import com.luckyoct.feature.profile.R import dagger.hilt.android.EntryPointAccessors -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest @Composable @@ -87,7 +86,7 @@ fun ProfileRoute( val viewModel = profileViewModel(profileSettingType = profileSettingType) val context = LocalContext.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val isInvalidNickname by viewModel.isInvalidNickname.collectAsStateWithLifecycle() + val isNicknameDuplicated by viewModel.isNicknameDuplicated.collectAsStateWithLifecycle() val isNotChangedProfileInput by viewModel.isNotChangedProfileInput.collectAsStateWithLifecycle() val keyboardController = LocalSoftwareKeyboardController.current @@ -125,16 +124,14 @@ fun ProfileRoute( uiState = uiState, profileSettingType = profileSettingType, isNotChangedProfileInput = isNotChangedProfileInput, - nickname = viewModel.nickname, onClickCharacter = { viewModel.selectCharacter(it) }, onClickSave = { keyboardController?.hide() viewModel.saveProfile(it) }, onBackClick = onBackClick, - isInvalidNickname = isInvalidNickname, + isNicknameDuplicated = isNicknameDuplicated, resetNicknameErrorState = { viewModel.resetNicknameErrorState() }, - onNicknameChanged = viewModel::updateNickname ) } } @@ -145,12 +142,10 @@ fun ProfileContent( uiState: ProfileUiState, profileSettingType: ProfileSettingType, isNotChangedProfileInput: Boolean, - nickname : String, onClickCharacter: (CharacterListItem) -> Unit = {}, onClickSave: (String) -> Unit = {}, onBackClick: (() -> Unit)? = null, - isInvalidNickname: Boolean, - onNicknameChanged : (String) -> Unit, + isNicknameDuplicated: Boolean, resetNicknameErrorState: () -> Unit ) { Column( @@ -176,13 +171,10 @@ fun ProfileContent( profileSettingType = profileSettingType, initialNickname = uiState.nickname, characters = uiState.characterList, - nickname = nickname, isNotChangedProfileInput = isNotChangedProfileInput, onClickCharacter = onClickCharacter, onClickSave = onClickSave, - isInvalidNickname = isInvalidNickname, - resetNicknameErrorState = resetNicknameErrorState, - onNicknameChanged = onNicknameChanged + isNicknameDuplicated = isNicknameDuplicated, ) } } @@ -196,16 +188,19 @@ fun ColumnScope.ProfileScreen( profileSettingType: ProfileSettingType, characters: List, isNotChangedProfileInput: Boolean, - nickname : String, onClickCharacter: (CharacterListItem) -> Unit, onClickSave: (String) -> Unit, - isInvalidNickname: Boolean, - onNicknameChanged : (String) -> Unit, - resetNicknameErrorState: () -> Unit = {} + isNicknameDuplicated: Boolean, ) { - // var nicknameInput by remember { mutableStateOf(initialNickname) } + var nicknameInput by remember { mutableStateOf(initialNickname) } val scrollState = rememberScrollState() val regex = Regex("^[가-힣ㅏ-ㅣㄱ-ㅎa-zA-Z0-9]{1,6}$") + var invalidNicknameError by remember { mutableStateOf(false) } + + LaunchedEffect(nicknameInput) { + if (nicknameInput.isEmpty()) return@LaunchedEffect + invalidNicknameError = (nicknameInput.length > 6 || regex.matches(nicknameInput).not()) + } Column( modifier = modifier @@ -224,7 +219,7 @@ fun ColumnScope.ProfileScreen( ), modifier = modifier .align(Alignment.CenterHorizontally) - .padding(top = if(profileSettingType == ProfileSettingType.SETTING) 0.dp else 56.dp), + .padding(top = if (profileSettingType == ProfileSettingType.SETTING) 0.dp else 56.dp), style = MissionMateTypography.heading_sm_bold, color = ColorGray1_FF404249 ) @@ -252,17 +247,11 @@ fun ColumnScope.ProfileScreen( .padding(top = 38.dp, start = 24.dp, end = 24.dp) .fillMaxWidth() .wrapContentHeight(), - text = nickname, - onValueChange = onNicknameChanged, -// { -// if (regex.matches(it) || it.isEmpty()) { -// nicknameInput = it -// } -// resetNicknameErrorState() -// }, + text = nicknameInput, + onValueChange = { nicknameInput = it }, hintId = R.string.nickname_hint, - guidanceId = if (isInvalidNickname) R.string.err_duplicated_nickname else R.string.nickname_input_guide, - isError = isInvalidNickname + guidanceId = if (isNicknameDuplicated) R.string.err_duplicated_nickname else R.string.nickname_input_guide, + isError = invalidNicknameError || isNicknameDuplicated ) } @@ -271,23 +260,26 @@ fun ColumnScope.ProfileScreen( .padding(bottom = 36.dp, start = 24.dp, end = 24.dp) .fillMaxWidth(), textId = R.string.save, - buttonType = - if (profileSettingType == ProfileSettingType.CREATE) { - if (nickname.trim().isEmpty()) { - MissionMateButtonType.DISABLED - } else { - MissionMateButtonType.ACTIVE + buttonType = when (profileSettingType) { + ProfileSettingType.CREATE -> { + if (nicknameInput.trim().isEmpty() || invalidNicknameError) { + MissionMateButtonType.DISABLED + } else { + MissionMateButtonType.ACTIVE + } } - } else { - if ((initialNickname == nickname && isNotChangedProfileInput) || - nickname.trim().isEmpty() - ) { - MissionMateButtonType.DISABLED - } else { - MissionMateButtonType.ACTIVE + + ProfileSettingType.SETTING -> { + if ((initialNickname == nicknameInput && isNotChangedProfileInput) || + nicknameInput.trim().isEmpty() || invalidNicknameError + ) { + MissionMateButtonType.DISABLED + } else { + MissionMateButtonType.ACTIVE + } } }, - onClick = { onClickSave(nickname) } + onClick = { onClickSave(nicknameInput) } ) } @@ -416,12 +408,10 @@ fun ColumnScope.ProfileScreenPreview() { backgroundResId = com.goalpanzi.mission_mate.core.designsystem.R.drawable.background_panda ), ), - nickname = "미션메이트", onClickCharacter = {}, onClickSave = {}, - isInvalidNickname = false, + isNicknameDuplicated = false, isNotChangedProfileInput = false, - onNicknameChanged = {} ) } diff --git a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt index a79cd362..f9b455c5 100644 --- a/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/java/com/goalpanzi/mission_mate/feature/profile/ProfileViewModel.kt @@ -1,8 +1,5 @@ package com.goalpanzi.mission_mate.feature.profile -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope @@ -46,17 +43,14 @@ class ProfileViewModel @AssistedInject constructor( private val defaultCharacters = CharacterListItem.createDefaultList() - var nickname by mutableStateOf("") - private set - private val _uiState = MutableStateFlow(ProfileUiState.Loading) val uiState = _uiState.asStateFlow() - private val _isInvalidNickname = MutableStateFlow(false) - val isInvalidNickname = _isInvalidNickname.asStateFlow() + private val _isNicknameDuplicated = MutableStateFlow(false) + val isNicknameDuplicated = _isNicknameDuplicated.asStateFlow() private val _isNotChangedProfileInput = MutableStateFlow(true) - val isNotChangedProfileInput : StateFlow = _isNotChangedProfileInput.asStateFlow() + val isNotChangedProfileInput: StateFlow = _isNotChangedProfileInput.asStateFlow() private val _isSaveSuccess = MutableSharedFlow() val isSaveSuccess = _isSaveSuccess.asSharedFlow() @@ -93,10 +87,19 @@ class ProfileViewModel @AssistedInject constructor( } } - fun updateNickname(input: String) { - nickname = input - - } +// fun updateNickname(input: String) { +// viewModelScope.launch { +// _invalidNicknameError.emit( +// if (input.length > 6) { +// InvalidNicknameError.TooLong +// } else if (input.contains(Regex("[^가-힣a-zA-Z0-9]"))) { +// InvalidNicknameError.IncludeSpecial +// } else { +// InvalidNicknameError.Duplicated +// } +// ) +// } +// } fun selectCharacter(character: CharacterListItem) { val state = uiState.value as? ProfileUiState.Success ?: return @@ -112,7 +115,7 @@ class ProfileViewModel @AssistedInject constructor( } fun resetNicknameErrorState() { - _isInvalidNickname.value = false + _isNicknameDuplicated.value = false } fun saveProfile(nickname: String) { @@ -122,7 +125,7 @@ class ProfileViewModel @AssistedInject constructor( it.isSelected } ?: return@launch - when( + when ( val response = profileUseCase .saveProfile( nickname = nickname, @@ -133,13 +136,14 @@ class ProfileViewModel @AssistedInject constructor( is NetworkResult.Success -> { _isSaveSuccess.emit(true) } + is NetworkResult.Exception -> {} is NetworkResult.Error -> { if (response.code == 409) { - _isInvalidNickname.emit(true) + _isNicknameDuplicated.emit(true) } } } } } -} \ No newline at end of file +}