From 4d60b41716f7952631b09193847e62a26480c6f0 Mon Sep 17 00:00:00 2001 From: Changyeop Lee Date: Thu, 22 Aug 2024 21:54:04 +0900 Subject: [PATCH] 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 +}