From 0563e32d28b90de3c389bd5f90c8ab3d6594d90f Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 14:55:29 +0900 Subject: [PATCH 01/31] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20Step=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20SignUpScreen=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../navigation/LoginSignupNavigation.kt | 13 +- .../loginsignup/signup/SignUpContract.kt | 44 ++++-- .../loginsignup/signup/SignUpScreen.kt | 144 ++++++++++++++---- .../loginsignup/signup/SignUpViewModel.kt | 34 +++-- 4 files changed, 182 insertions(+), 53 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt index 1be813c8..ce120fe1 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt @@ -6,7 +6,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.susu.feature.loginsignup.VoteRoute import com.susu.feature.loginsignup.login.LoginRoute -import com.susu.feature.loginsignup.signup.SignUpScreen +import com.susu.feature.loginsignup.signup.SignUpRoute @Suppress("unused") fun NavController.navigateLoginSignup(navOptions: NavOptions) { @@ -45,8 +45,17 @@ fun NavGraphBuilder.loginSignupNavGraph( ) } composable(route = LoginSignupRoute.Parent.SignUp.route) { - SignUpScreen( + SignUpRoute( navigateToReceived = navigateToReceived, + navigateToLogin = { + navController.navigate(LoginSignupRoute.Parent.Login.route) { + popUpTo( + route = LoginSignupRoute.Parent.Vote.route, + ) { + inclusive = true + } + } + }, ) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index d0bc2ff9..d9d47fb9 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -3,15 +3,39 @@ package com.susu.feature.loginsignup.signup import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -sealed interface SignUpContract { - sealed class SignUpEffect : SideEffect { - data object NavigateToReceived : SignUpEffect() - data class ShowToast(val msg: String) : SignUpEffect() - } +sealed class SignUpEffect : SideEffect { + data object NavigateToLogin : SignUpEffect() + data object NavigateToReceived : SignUpEffect() + data class ShowToast(val msg: String) : SignUpEffect() +} + +data class SignUpState( + val isNextStepAvailable: Boolean = true, + val currentStep: SignUpStep = SignUpStep.TERMS, + val terms: List = emptyList(), + val name: String = "", + val gender: Gender = Gender.NONE, + val birth: Int = 1930, +) : UiState + +enum class SignUpStep( + val appBarTitle: String, + val description: String, +) { + TERMS( + appBarTitle = "약관 동의", + description = "서비스 약관을 위해\n약관에 동의해주세요", + ), + NAME( + appBarTitle = "", + description = "반가워요!\n이름을 알려주세요", + ), + ADDITIONAL( + appBarTitle = "", + description = "아래 정보들을 알려주시면\n통계를 알려드릴 수 있어요", + ), +} - data class SignUpState( - val name: String = "", - val gender: String = "M", - val birth: String = "0", - ) : UiState +enum class Gender(val content: String) { + NONE(""), MALE("M"), FEMALE("F") } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 6a5aebd6..87655755 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -1,61 +1,141 @@ package com.susu.feature.loginsignup.signup -import android.widget.Toast +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.core.tween +import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Button +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon import androidx.compose.material3.Text -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.susu.core.designsystem.R +import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar +import com.susu.core.designsystem.component.appbar.SusuProgressAppBar +import com.susu.core.designsystem.component.button.FilledButtonColor +import com.susu.core.designsystem.component.button.MediumButtonStyle +import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.susuClickable @Composable -fun SignUpScreen( +fun SignUpRoute( viewModel: SignUpViewModel = hiltViewModel(), navigateToReceived: () -> Unit, + navigateToLogin: () -> Unit, ) { - val uiState by viewModel.uiState.collectAsState() - val context = LocalContext.current + val uiState: SignUpState by viewModel.uiState.collectAsStateWithLifecycle() LaunchedEffect(key1 = viewModel.sideEffect) { viewModel.sideEffect.collect { sideEffect -> when (sideEffect) { - SignUpContract.SignUpEffect.NavigateToReceived -> { - Toast.makeText(context, "가입 성공", Toast.LENGTH_SHORT).show() - navigateToReceived() + SignUpEffect.NavigateToLogin -> navigateToLogin() + SignUpEffect.NavigateToReceived -> navigateToReceived() + is SignUpEffect.ShowToast -> {} + } + } + } + + SignUpScreen( + uiState = uiState, + onPreviousPressed = viewModel::goPreviousStep, + onNextPressed = viewModel::goNextStep, + ) { + AnimatedContent( + modifier = Modifier.weight(1f), + targetState = uiState, + label = "SignUpContent", + transitionSpec = { + val direction = if (targetState.currentStep.ordinal > initialState.currentStep.ordinal) + AnimatedContentTransitionScope.SlideDirection.Left + else AnimatedContentTransitionScope.SlideDirection.Right + slideIntoContainer( + towards = direction, + animationSpec = tween(500), + ) togetherWith slideOutOfContainer( + towards = direction, + animationSpec = tween(500), + ) + }, + ) { targetState -> + when (targetState.currentStep) { + SignUpStep.TERMS -> { + Text(text = targetState.currentStep.description) + } + + SignUpStep.NAME -> { + Text(text = targetState.currentStep.description) } - is SignUpContract.SignUpEffect.ShowToast -> { - Toast.makeText(context, sideEffect.msg, Toast.LENGTH_SHORT).show() + SignUpStep.ADDITIONAL -> { + Text(text = targetState.currentStep.description) } } } } +} - Column { - TextField( - value = uiState.name, - onValueChange = viewModel::updateName, - label = { Text(text = "이름") }, - ) - TextField( - value = uiState.gender, - onValueChange = viewModel::updateGender, - label = { - Text(text = "성별 (M/F)") - }, +@Composable +fun SignUpScreen( + uiState: SignUpState = SignUpState(), + onPreviousPressed: () -> Unit = {}, + onNextPressed: () -> Unit = {}, + content: @Composable ColumnScope.() -> Unit = {}, +) { + Column( + modifier = Modifier.fillMaxSize(), + ) { + if (uiState.currentStep == SignUpStep.TERMS) { + SusuDefaultAppBar( + leftIcon = { + Icon( + painter = painterResource(id = R.drawable.ic_arrow_left), + contentDescription = "뒤로가기", + modifier = Modifier.susuClickable( + rippleEnabled = true, + onClick = onPreviousPressed, + ).padding(10.dp), + ) + }, + title = uiState.currentStep.appBarTitle, + ) + } else { + SusuProgressAppBar( + leftIcon = R.drawable.ic_arrow_left, + currentStep = SignUpStep.entries.indexOf(uiState.currentStep), + entireStep = SignUpStep.entries.size - 1, + onClickBackButton = onPreviousPressed, + ) + } + content() + SusuFilledButton( + modifier = Modifier.fillMaxWidth(), + color = FilledButtonColor.Black, + style = MediumButtonStyle.height60, + text = "다음", + isActive = uiState.isNextStepAvailable, + onClick = onNextPressed, ) - TextField( - value = uiState.birth, - onValueChange = { viewModel.updateBirth(it) }, - label = { Text(text = "출생년도 (1930 ~ 2030)") }, + } +} - ) - Button(onClick = viewModel::signUp) { - Text(text = "회원가입") +@Preview +@Composable +fun SignUpScreenPreview() { + SusuTheme { + SignUpScreen { + Text("hello", modifier = Modifier.fillMaxWidth().weight(1f)) } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index 7bb4f8f8..bd4e8695 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -12,21 +12,37 @@ import javax.inject.Inject @HiltViewModel class SignUpViewModel @Inject constructor( private val signUpUseCase: SignUpUseCase, -) : BaseViewModel(SignUpContract.SignUpState()) { +) : BaseViewModel(SignUpState()) { fun updateName(name: String) { intent { copy(name = name) } } - fun updateGender(gender: String) { + fun updateGender(gender: Gender) { intent { copy(gender = gender) } } - fun updateBirth(birth: String) { + fun updateBirth(birth: Int) { intent { copy(birth = birth) } } - fun signUp() { + fun goNextStep() { + when (uiState.value.currentStep) { + SignUpStep.TERMS -> intent { copy(currentStep = SignUpStep.NAME) } + SignUpStep.NAME -> intent { copy(currentStep = SignUpStep.ADDITIONAL) } + SignUpStep.ADDITIONAL -> signUp() + } + } + + fun goPreviousStep() { + when (uiState.value.currentStep) { + SignUpStep.TERMS -> postSideEffect(SignUpEffect.NavigateToLogin) + SignUpStep.NAME -> intent { copy(currentStep = SignUpStep.TERMS) } + SignUpStep.ADDITIONAL -> intent { copy(currentStep = SignUpStep.NAME) } + } + } + + private fun signUp() { KakaoLoginHelper.getAccessToken { oauthAccessToken -> viewModelScope.launch { if (oauthAccessToken != null) { @@ -34,16 +50,16 @@ class SignUpViewModel @Inject constructor( oauthAccessToken = oauthAccessToken, user = User( name = uiState.value.name, - gender = uiState.value.gender, - birth = uiState.value.birth.toInt(), + gender = uiState.value.gender.content, + birth = uiState.value.birth, ), ).onSuccess { - postSideEffect(SignUpContract.SignUpEffect.NavigateToReceived) + postSideEffect(SignUpEffect.NavigateToReceived) }.onFailure { - postSideEffect(SignUpContract.SignUpEffect.ShowToast(it.message ?: "에러 발생")) + postSideEffect(SignUpEffect.ShowToast(it.message ?: "에러 발생")) } } else { - postSideEffect(SignUpContract.SignUpEffect.ShowToast("카카오톡 로그인 에러 발생")) + postSideEffect(SignUpEffect.ShowToast("카카오톡 로그인 에러 발생")) } } } From 3140cb378e0c4dfd7825be0faa68e38ae93a8af9 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 15:07:15 +0900 Subject: [PATCH 02/31] =?UTF-8?q?refactor:=20SusuProgressAppBar=20slot=20A?= =?UTF-8?q?pi=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20BackIcon=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/appbar/SusuProgressAppBar.kt | 39 +++---------------- .../loginsignup/signup/SignUpScreen.kt | 28 ++++++------- 2 files changed, 18 insertions(+), 49 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt index 458407c0..2ba54e7b 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt @@ -1,13 +1,9 @@ package com.susu.core.designsystem.component.appbar -import android.util.Log -import androidx.annotation.DrawableRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Button -import androidx.compose.material3.Icon import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -16,41 +12,22 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.susu.core.designsystem.R +import com.susu.core.designsystem.component.appbar.icon.BackIcon import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.ui.extension.susuClickable @Composable fun SusuProgressAppBar( modifier: Modifier = Modifier, - @DrawableRes leftIcon: Int? = null, - leftIconContentDescription: String? = null, - leftIconPadding: Dp = SusuTheme.spacing.spacing_xs, + leftIcon: @Composable () -> Unit = {}, currentStep: Int, entireStep: Int, progressBar: ProgressBarStyle = ProgressBarStyle.SusuProgressBar, - onClickBackButton: () -> Unit, ) { BasicAppBar( modifier = modifier, - leftIcon = { - leftIcon?.let { - Icon( - painter = painterResource(id = leftIcon), - contentDescription = leftIconContentDescription, - modifier = Modifier - .susuClickable( - rippleEnabled = true, - onClick = onClickBackButton, - ) - .padding(leftIconPadding), - ) - } - }, + leftIcon = leftIcon, title = { LinearProgressIndicator( progress = { currentStep / entireStep.toFloat() }, @@ -66,25 +43,21 @@ fun SusuProgressAppBar( }, ) } - @Preview(showBackground = true, backgroundColor = 0xFFFFFFFF) @Composable fun SusuProgressAppBarPreview() { val entireStep = 6 var currentStep by remember { mutableStateOf(1) } - SusuTheme { Column( verticalArrangement = Arrangement.spacedBy(20.dp), ) { SusuProgressAppBar( - leftIcon = R.drawable.ic_arrow_left, - leftIconContentDescription = "뒤로가기", + leftIcon = { + BackIcon() + }, currentStep = currentStep, entireStep = entireStep, - onClickBackButton = { - Log.d("확인", "왼쪽 뒤로가기 클릭") - }, ) Button( onClick = { diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 87655755..75227489 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -8,26 +8,21 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.susu.core.designsystem.R import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.SusuProgressAppBar +import com.susu.core.designsystem.component.appbar.icon.BackIcon import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.ui.extension.susuClickable @Composable fun SignUpRoute( @@ -99,23 +94,22 @@ fun SignUpScreen( if (uiState.currentStep == SignUpStep.TERMS) { SusuDefaultAppBar( leftIcon = { - Icon( - painter = painterResource(id = R.drawable.ic_arrow_left), - contentDescription = "뒤로가기", - modifier = Modifier.susuClickable( - rippleEnabled = true, - onClick = onPreviousPressed, - ).padding(10.dp), + BackIcon( + onClick = onPreviousPressed ) }, title = uiState.currentStep.appBarTitle, ) } else { SusuProgressAppBar( - leftIcon = R.drawable.ic_arrow_left, + leftIcon = { + BackIcon( + onClick = onPreviousPressed + ) + }, currentStep = SignUpStep.entries.indexOf(uiState.currentStep), entireStep = SignUpStep.entries.size - 1, - onClickBackButton = onPreviousPressed, + ) } content() @@ -135,7 +129,9 @@ fun SignUpScreen( fun SignUpScreenPreview() { SusuTheme { SignUpScreen { - Text("hello", modifier = Modifier.fillMaxWidth().weight(1f)) + Text("hello", modifier = Modifier + .fillMaxWidth() + .weight(1f)) } } } From 632df6b60a2c4adaf5ab1840d8935e7deefb262c Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 15:08:02 +0900 Subject: [PATCH 03/31] =?UTF-8?q?chore:=20=EB=8B=A4=EC=9D=8C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20shape=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/feature/loginsignup/signup/SignUpScreen.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 75227489..34614b37 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -115,6 +116,7 @@ fun SignUpScreen( content() SusuFilledButton( modifier = Modifier.fillMaxWidth(), + shape = RectangleShape, color = FilledButtonColor.Black, style = MediumButtonStyle.height60, text = "다음", From ec2ae22813f0b1fb4da1f69cb12751f0d65ca5d1 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 17:51:27 +0900 Subject: [PATCH 04/31] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=20=EB=8F=99?= =?UTF-8?q?=EC=9D=98=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/susu/core/model/Term.kt | 7 + .../java/com/susu/core/model/TermDetail.kt | 8 + .../loginsignup/signup/SignUpContract.kt | 12 +- .../loginsignup/signup/SignUpScreen.kt | 65 +++++-- .../loginsignup/signup/SignUpViewModel.kt | 24 +++ .../signup/content/TermsContent.kt | 176 ++++++++++++++++++ 6 files changed, 274 insertions(+), 18 deletions(-) create mode 100644 core/model/src/main/java/com/susu/core/model/Term.kt create mode 100644 core/model/src/main/java/com/susu/core/model/TermDetail.kt create mode 100644 feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt diff --git a/core/model/src/main/java/com/susu/core/model/Term.kt b/core/model/src/main/java/com/susu/core/model/Term.kt new file mode 100644 index 00000000..fee956dd --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/Term.kt @@ -0,0 +1,7 @@ +package com.susu.core.model + +data class Term( + val id: Int, + val title: String, + val isEssential: Boolean, +) diff --git a/core/model/src/main/java/com/susu/core/model/TermDetail.kt b/core/model/src/main/java/com/susu/core/model/TermDetail.kt new file mode 100644 index 00000000..2a46e3e8 --- /dev/null +++ b/core/model/src/main/java/com/susu/core/model/TermDetail.kt @@ -0,0 +1,8 @@ +package com.susu.core.model + +data class TermDetail( + val id: Int, + val title: String, + val isEssential: Boolean, + val description: String +) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index d9d47fb9..1e855008 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -10,9 +10,8 @@ sealed class SignUpEffect : SideEffect { } data class SignUpState( - val isNextStepAvailable: Boolean = true, val currentStep: SignUpStep = SignUpStep.TERMS, - val terms: List = emptyList(), + val agreedTerms: List = emptyList(), val name: String = "", val gender: Gender = Gender.NONE, val birth: Int = 1930, @@ -21,18 +20,27 @@ data class SignUpState( enum class SignUpStep( val appBarTitle: String, val description: String, + val bottomButtonText: String, ) { TERMS( appBarTitle = "약관 동의", description = "서비스 약관을 위해\n약관에 동의해주세요", + bottomButtonText = "다음", + ), + TERM_DETAIL( + appBarTitle = "서비스 이용 약관", + description = "", + bottomButtonText = "동의하기", ), NAME( appBarTitle = "", description = "반가워요!\n이름을 알려주세요", + bottomButtonText = "다음", ), ADDITIONAL( appBarTitle = "", description = "아래 정보들을 알려주시면\n통계를 알려드릴 수 있어요", + bottomButtonText = "다음", ), } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 34614b37..7fa7446a 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -24,6 +24,8 @@ import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Term +import com.susu.feature.loginsignup.signup.content.TermsContent @Composable fun SignUpRoute( @@ -45,15 +47,26 @@ fun SignUpRoute( SignUpScreen( uiState = uiState, + isNextStepActive = when (uiState.currentStep) { + SignUpStep.TERMS -> uiState.agreedTerms.containsAll(listOf(1, 2)) + SignUpStep.TERM_DETAIL -> true + SignUpStep.NAME -> true + SignUpStep.ADDITIONAL -> true + }, onPreviousPressed = viewModel::goPreviousStep, - onNextPressed = viewModel::goNextStep, + onNextPressed = { + if (uiState.currentStep == SignUpStep.TERM_DETAIL) { + // TODO: 현재 보고 있던 약관 동의 + } + viewModel.goNextStep() + }, ) { AnimatedContent( modifier = Modifier.weight(1f), - targetState = uiState, + targetState = uiState.currentStep, label = "SignUpContent", transitionSpec = { - val direction = if (targetState.currentStep.ordinal > initialState.currentStep.ordinal) + val direction = if (targetState.ordinal > initialState.ordinal) AnimatedContentTransitionScope.SlideDirection.Left else AnimatedContentTransitionScope.SlideDirection.Right slideIntoContainer( @@ -65,17 +78,34 @@ fun SignUpRoute( ) }, ) { targetState -> - when (targetState.currentStep) { + when (targetState) { SignUpStep.TERMS -> { - Text(text = targetState.currentStep.description) + TermsContent( + modifier = Modifier.fillMaxSize(), + descriptionText = targetState.description, + terms = listOf( + Term(id = 1, title = "아무개 약관", isEssential = true), + Term(id = 2, title = "아무개 약관", isEssential = true), + ), + agreedTerms = uiState.agreedTerms, + onDetailClick = viewModel::goTermDetail, + onSelectAll = { if (it) viewModel.agreeAllTerms() else viewModel.disagreeAllTerms() }, + onTermChecked = { agree, id -> + if (agree) viewModel.agreeTerm(id) else viewModel.disagreeTerm(id) + }, + ) } SignUpStep.NAME -> { - Text(text = targetState.currentStep.description) + Text(text = targetState.description) } SignUpStep.ADDITIONAL -> { - Text(text = targetState.currentStep.description) + Text(text = targetState.description) + } + + SignUpStep.TERM_DETAIL -> { + Text(text = targetState.description) } } } @@ -85,6 +115,7 @@ fun SignUpRoute( @Composable fun SignUpScreen( uiState: SignUpState = SignUpState(), + isNextStepActive: Boolean = false, onPreviousPressed: () -> Unit = {}, onNextPressed: () -> Unit = {}, content: @Composable ColumnScope.() -> Unit = {}, @@ -92,11 +123,11 @@ fun SignUpScreen( Column( modifier = Modifier.fillMaxSize(), ) { - if (uiState.currentStep == SignUpStep.TERMS) { + if (uiState.currentStep == SignUpStep.TERMS || uiState.currentStep == SignUpStep.TERM_DETAIL) { SusuDefaultAppBar( leftIcon = { BackIcon( - onClick = onPreviousPressed + onClick = onPreviousPressed, ) }, title = uiState.currentStep.appBarTitle, @@ -105,12 +136,11 @@ fun SignUpScreen( SusuProgressAppBar( leftIcon = { BackIcon( - onClick = onPreviousPressed + onClick = onPreviousPressed, ) }, currentStep = SignUpStep.entries.indexOf(uiState.currentStep), entireStep = SignUpStep.entries.size - 1, - ) } content() @@ -119,8 +149,8 @@ fun SignUpScreen( shape = RectangleShape, color = FilledButtonColor.Black, style = MediumButtonStyle.height60, - text = "다음", - isActive = uiState.isNextStepAvailable, + text = uiState.currentStep.bottomButtonText, + isActive = isNextStepActive, onClick = onNextPressed, ) } @@ -131,9 +161,12 @@ fun SignUpScreen( fun SignUpScreenPreview() { SusuTheme { SignUpScreen { - Text("hello", modifier = Modifier - .fillMaxWidth() - .weight(1f)) + Text( + "hello", + modifier = Modifier + .fillMaxWidth() + .weight(1f), + ) } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index bd4e8695..fe69752b 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -26,9 +26,27 @@ class SignUpViewModel @Inject constructor( intent { copy(birth = birth) } } + fun agreeTerm(termId: Int) { + intent { copy(agreedTerms = agreedTerms + termId) } + } + + fun disagreeTerm(termId: Int) { + intent { copy(agreedTerms = agreedTerms - termId) } + } + + fun agreeAllTerms() { + // TODO: 약관 정보 받아오기 + intent { copy(agreedTerms = listOf(1, 2)) } + } + + fun disagreeAllTerms() { + intent { copy(agreedTerms = emptyList()) } + } + fun goNextStep() { when (uiState.value.currentStep) { SignUpStep.TERMS -> intent { copy(currentStep = SignUpStep.NAME) } + SignUpStep.TERM_DETAIL -> intent { copy(currentStep = SignUpStep.TERMS) } SignUpStep.NAME -> intent { copy(currentStep = SignUpStep.ADDITIONAL) } SignUpStep.ADDITIONAL -> signUp() } @@ -37,11 +55,17 @@ class SignUpViewModel @Inject constructor( fun goPreviousStep() { when (uiState.value.currentStep) { SignUpStep.TERMS -> postSideEffect(SignUpEffect.NavigateToLogin) + SignUpStep.TERM_DETAIL -> intent { copy(currentStep = SignUpStep.TERMS) } SignUpStep.NAME -> intent { copy(currentStep = SignUpStep.TERMS) } SignUpStep.ADDITIONAL -> intent { copy(currentStep = SignUpStep.NAME) } } } + fun goTermDetail(termId: Int) { + // TODO: termId에 맞는 화면 표시 + intent { copy(currentStep = SignUpStep.TERM_DETAIL) } + } + private fun signUp() { KakaoLoginHelper.getAccessToken { oauthAccessToken -> viewModelScope.launch { diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt new file mode 100644 index 00000000..3ef4eb4b --- /dev/null +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt @@ -0,0 +1,176 @@ +package com.susu.feature.loginsignup.signup.content + +import androidx.compose.foundation.Image +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.component.badge.BadgeColor +import com.susu.core.designsystem.component.badge.BadgeStyle +import com.susu.core.designsystem.component.badge.SusuBadge +import com.susu.core.designsystem.theme.Gray100 +import com.susu.core.designsystem.theme.Gray15 +import com.susu.core.designsystem.theme.Gray30 +import com.susu.core.designsystem.theme.Gray40 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.model.Term +import com.susu.core.ui.extension.susuClickable +import com.susu.core.ui.R + +@Composable +fun TermsContent( + modifier: Modifier = Modifier, + descriptionText: String = "", + terms: List = emptyList(), + agreedTerms: List = emptyList(), + onDetailClick: (termId: Int) -> Unit = {}, + onSelectAll: (agree: Boolean) -> Unit = {}, + onTermChecked: (agree: Boolean, id: Int) -> Unit = { _, _ -> }, +) { + Column( + modifier = modifier.padding(16.dp), + ) { + Text( + text = descriptionText, + style = SusuTheme.typography.title_m, + ) + Spacer(modifier = Modifier.height(24.dp)) + TermListItem( + title = "전체 동의하기", + checked = agreedTerms.containsAll(terms.map { it.id }), + isEssential = false, + canRead = false, + onCheckClick = { onSelectAll(it) }, + ) + HorizontalDivider( + thickness = 1.dp, + color = Gray30, + ) + terms.forEach { term -> + TermListItem( + title = term.title, + checked = agreedTerms.contains(term.id), + isEssential = term.isEssential, + onDetailClick = { onDetailClick(term.id) }, + onCheckClick = { + onTermChecked(it, term.id) + }, + ) + } + } +} + +@Composable +fun TermListItem( + modifier: Modifier = Modifier, + title: String = "", + checked: Boolean = false, + isEssential: Boolean = true, + canRead: Boolean = true, + onCheckClick: (Boolean) -> Unit = {}, + onDetailClick: () -> Unit = {}, +) { + Row( + modifier = modifier.padding(vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + TermCheckCircle(isChecked = checked, onCheckedChange = onCheckClick) + Spacer(modifier = Modifier.width(16.dp)) + if (isEssential) { + SusuBadge(color = BadgeColor.Blue60, text = "필수", padding = BadgeStyle.smallBadge) + Spacer(modifier = Modifier.width(8.dp)) + } + Text( + modifier = Modifier.weight(1f), + text = title, + style = SusuTheme.typography.title_xxs, + ) + if (canRead) { + Spacer(modifier = Modifier.width(16.dp)) + Image( + modifier = Modifier + .size(20.dp) + .susuClickable(rippleEnabled = false, onClick = onDetailClick), + painter = painterResource(id = R.drawable.ic_arrow_right), + contentDescription = "약관 보기", + ) + } + } +} + +@Composable +fun TermCheckCircle( + modifier: Modifier = Modifier, + isChecked: Boolean, + onCheckedChange: (Boolean) -> Unit = {}, +) { + Box( + modifier = modifier + .size(20.dp) + .drawBehind { + if (isChecked) { + drawCircle( + color = Gray100, + radius = 8.dp.toPx(), + ) + } else { + drawCircle( + color = Gray40, + radius = 8.dp.toPx(), + style = Stroke(width = 1.dp.toPx()), + ) + } + } + .susuClickable( + rippleEnabled = false, + onClick = { onCheckedChange(isChecked.not()) }, + ), + ) { + if (isChecked) { + Icon( + modifier = Modifier.padding(2.dp), + imageVector = Icons.Rounded.Check, + contentDescription = null, + tint = Gray15, + ) + } + } +} + +@Preview(showSystemUi = true) +@Composable +fun TermsContentPreview() { + SusuTheme { + TermsContent( + modifier = Modifier.fillMaxSize(), + descriptionText = "어쩌구저쩌구\n뭐를해주세요", + terms = listOf(Term(1, "노예 계약", true), Term(2, "농노 계약", true)), + ) + } +} + +@Preview +@Composable +fun TermCheckCirclePreview() { + SusuTheme { + TermCheckCircle(isChecked = true) + } +} From 693a6f08d7b544200f0ce708b3919803c4995aab Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 19:05:28 +0900 Subject: [PATCH 05/31] =?UTF-8?q?feat:=20=EC=95=BD=EA=B4=80=20api=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/data/data/di/RepositoryModule.kt | 7 ++++ .../data/repository/TermRepositoryImpl.kt | 16 +++++++++ .../com/susu/data/remote/api/TermService.kt | 15 ++++++++ .../susu/data/remote/di/ApiServiceModule.kt | 8 +++++ .../remote/model/response/TermResponse.kt | 33 +++++++++++++++++ .../susu/domain/repository/TermRepository.kt | 9 +++++ .../loginsignup/GetTermDetailUseCase.kt | 14 ++++++++ .../usecase/loginsignup/GetTermsUseCase.kt | 14 ++++++++ .../loginsignup/signup/SignUpScreen.kt | 31 +++++++++++----- .../loginsignup/signup/SignUpViewModel.kt | 8 ++--- .../loginsignup/signup/TermContract.kt | 13 +++++++ .../loginsignup/signup/TermViewModel.kt | 36 +++++++++++++++++++ 12 files changed, 190 insertions(+), 14 deletions(-) create mode 100644 data/src/main/java/com/susu/data/data/repository/TermRepositoryImpl.kt create mode 100644 data/src/main/java/com/susu/data/remote/api/TermService.kt create mode 100644 data/src/main/java/com/susu/data/remote/model/response/TermResponse.kt create mode 100644 domain/src/main/java/com/susu/domain/repository/TermRepository.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermDetailUseCase.kt create mode 100644 domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermsUseCase.kt create mode 100644 feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt create mode 100644 feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt diff --git a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt index 738c59fe..a9b67d77 100644 --- a/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt +++ b/data/src/main/java/com/susu/data/data/di/RepositoryModule.kt @@ -3,10 +3,12 @@ package com.susu.data.data.di import com.susu.data.data.repository.LedgerRecentSearchRepositoryImpl import com.susu.data.data.repository.LoginRepositoryImpl import com.susu.data.data.repository.SignUpRepositoryImpl +import com.susu.data.data.repository.TermRepositoryImpl import com.susu.data.data.repository.TokenRepositoryImpl import com.susu.domain.repository.LedgerRecentSearchRepository import com.susu.domain.repository.LoginRepository import com.susu.domain.repository.SignUpRepository +import com.susu.domain.repository.TermRepository import com.susu.domain.repository.TokenRepository import dagger.Binds import dagger.Module @@ -36,4 +38,9 @@ abstract class RepositoryModule { abstract fun bindLedgerRecentSearchRepository( ledgerRecentSearchRepositoryImpl: LedgerRecentSearchRepositoryImpl, ): LedgerRecentSearchRepository + + @Binds + abstract fun bindTermRepository( + termRepositoryImpl: TermRepositoryImpl, + ): TermRepository } diff --git a/data/src/main/java/com/susu/data/data/repository/TermRepositoryImpl.kt b/data/src/main/java/com/susu/data/data/repository/TermRepositoryImpl.kt new file mode 100644 index 00000000..a378afc2 --- /dev/null +++ b/data/src/main/java/com/susu/data/data/repository/TermRepositoryImpl.kt @@ -0,0 +1,16 @@ +package com.susu.data.data.repository + +import com.susu.core.model.Term +import com.susu.core.model.TermDetail +import com.susu.data.remote.api.TermService +import com.susu.data.remote.model.response.toModel +import com.susu.domain.repository.TermRepository +import javax.inject.Inject + +class TermRepositoryImpl @Inject constructor( + private val termService: TermService, +) : TermRepository { + override suspend fun getTerms(): List = termService.getTerms().getOrThrow().map { it.toModel() } + + override suspend fun getTermDetail(id: Int): TermDetail = termService.getTermDetail(id).getOrThrow().toModel() +} diff --git a/data/src/main/java/com/susu/data/remote/api/TermService.kt b/data/src/main/java/com/susu/data/remote/api/TermService.kt new file mode 100644 index 00000000..e507eaa5 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/api/TermService.kt @@ -0,0 +1,15 @@ +package com.susu.data.remote.api + +import com.susu.data.remote.model.response.TermDetailResponse +import com.susu.data.remote.model.response.TermResponse +import com.susu.data.remote.retrofit.ApiResult +import retrofit2.http.GET +import retrofit2.http.Path + +interface TermService { + @GET("terms") + suspend fun getTerms(): ApiResult> + + @GET("terms/{id}") + suspend fun getTermDetail(@Path("id") id: Int): ApiResult +} diff --git a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt index 3648ddb7..7ddec6cc 100644 --- a/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt +++ b/data/src/main/java/com/susu/data/remote/di/ApiServiceModule.kt @@ -1,6 +1,7 @@ package com.susu.data.remote.di import com.susu.data.remote.api.SignUpService +import com.susu.data.remote.api.TermService import com.susu.data.remote.api.TokenService import com.susu.data.remote.api.UserService import dagger.Module @@ -8,6 +9,7 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import retrofit2.Retrofit +import retrofit2.create import javax.inject.Singleton @Module @@ -31,4 +33,10 @@ object ApiServiceModule { fun provideTokenService(@AuthRetrofit retrofit: Retrofit): TokenService { return retrofit.create(TokenService::class.java) } + + @Singleton + @Provides + fun providesTermService(retrofit: Retrofit): TermService { + return retrofit.create(TermService::class.java) + } } diff --git a/data/src/main/java/com/susu/data/remote/model/response/TermResponse.kt b/data/src/main/java/com/susu/data/remote/model/response/TermResponse.kt new file mode 100644 index 00000000..dea1c6e1 --- /dev/null +++ b/data/src/main/java/com/susu/data/remote/model/response/TermResponse.kt @@ -0,0 +1,33 @@ +package com.susu.data.remote.model.response + +import com.susu.core.model.Term +import com.susu.core.model.TermDetail +import kotlinx.serialization.Serializable + +@Serializable +data class TermResponse( + val id: Int, + val title: String, + val isEssential: Boolean, +) + +@Serializable +data class TermDetailResponse( + val id: Int, + val title: String, + val description: String, + val isEssential: Boolean, +) + +fun TermResponse.toModel(): Term = Term( + id = id, + title = title, + isEssential = isEssential, +) + +fun TermDetailResponse.toModel(): TermDetail = TermDetail( + id = id, + title = title, + description = description, + isEssential = isEssential, +) diff --git a/domain/src/main/java/com/susu/domain/repository/TermRepository.kt b/domain/src/main/java/com/susu/domain/repository/TermRepository.kt new file mode 100644 index 00000000..b5f645c8 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/repository/TermRepository.kt @@ -0,0 +1,9 @@ +package com.susu.domain.repository + +import com.susu.core.model.Term +import com.susu.core.model.TermDetail + +interface TermRepository { + suspend fun getTerms(): List + suspend fun getTermDetail(id: Int): TermDetail +} diff --git a/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermDetailUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermDetailUseCase.kt new file mode 100644 index 00000000..f520fb5e --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermDetailUseCase.kt @@ -0,0 +1,14 @@ +package com.susu.domain.usecase.loginsignup + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.TermRepository +import javax.inject.Inject + +class GetTermDetailUseCase @Inject constructor( + private val termRepository: TermRepository, +) { + + suspend operator fun invoke(termId: Int) = runCatchingIgnoreCancelled { + termRepository.getTermDetail(termId) + } +} diff --git a/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermsUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermsUseCase.kt new file mode 100644 index 00000000..d3b1178e --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/loginsignup/GetTermsUseCase.kt @@ -0,0 +1,14 @@ +package com.susu.domain.usecase.loginsignup + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.TermRepository +import javax.inject.Inject + +class GetTermsUseCase @Inject constructor( + private val termRepository: TermRepository, +) { + + suspend operator fun invoke() = runCatchingIgnoreCancelled { + termRepository.getTerms() + } +} diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 7fa7446a..732d2b75 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -15,6 +16,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar @@ -24,16 +26,17 @@ import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme -import com.susu.core.model.Term import com.susu.feature.loginsignup.signup.content.TermsContent @Composable fun SignUpRoute( viewModel: SignUpViewModel = hiltViewModel(), + termViewModel: TermViewModel = hiltViewModel(), navigateToReceived: () -> Unit, navigateToLogin: () -> Unit, ) { val uiState: SignUpState by viewModel.uiState.collectAsStateWithLifecycle() + val termState: TermState by termViewModel.uiState.collectAsStateWithLifecycle() LaunchedEffect(key1 = viewModel.sideEffect) { viewModel.sideEffect.collect { sideEffect -> @@ -56,7 +59,7 @@ fun SignUpRoute( onPreviousPressed = viewModel::goPreviousStep, onNextPressed = { if (uiState.currentStep == SignUpStep.TERM_DETAIL) { - // TODO: 현재 보고 있던 약관 동의 + viewModel.agreeTerm(termState.currentTerm.id) } viewModel.goNextStep() }, @@ -83,13 +86,19 @@ fun SignUpRoute( TermsContent( modifier = Modifier.fillMaxSize(), descriptionText = targetState.description, - terms = listOf( - Term(id = 1, title = "아무개 약관", isEssential = true), - Term(id = 2, title = "아무개 약관", isEssential = true), - ), + terms = termState.terms, agreedTerms = uiState.agreedTerms, - onDetailClick = viewModel::goTermDetail, - onSelectAll = { if (it) viewModel.agreeAllTerms() else viewModel.disagreeAllTerms() }, + onDetailClick = { + termViewModel.updateCurrentTerm(it) + viewModel.goTermDetail() + }, + onSelectAll = { agree -> + if (agree) { + viewModel.agreeAllTerms(termState.terms.map { it.id }) + } else { + viewModel.disagreeAllTerms() + } + }, onTermChecked = { agree, id -> if (agree) viewModel.agreeTerm(id) else viewModel.disagreeTerm(id) }, @@ -105,7 +114,11 @@ fun SignUpRoute( } SignUpStep.TERM_DETAIL -> { - Text(text = targetState.description) + Text( + modifier = Modifier.fillMaxSize().padding(16.dp), + text = termState.currentTerm.description, + style = SusuTheme.typography.text_xxxs, + ) } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index fe69752b..890412bc 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -34,9 +34,8 @@ class SignUpViewModel @Inject constructor( intent { copy(agreedTerms = agreedTerms - termId) } } - fun agreeAllTerms() { - // TODO: 약관 정보 받아오기 - intent { copy(agreedTerms = listOf(1, 2)) } + fun agreeAllTerms(entireTermIds: List) { + intent { copy(agreedTerms = entireTermIds) } } fun disagreeAllTerms() { @@ -61,8 +60,7 @@ class SignUpViewModel @Inject constructor( } } - fun goTermDetail(termId: Int) { - // TODO: termId에 맞는 화면 표시 + fun goTermDetail() { intent { copy(currentStep = SignUpStep.TERM_DETAIL) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt new file mode 100644 index 00000000..85a003c6 --- /dev/null +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt @@ -0,0 +1,13 @@ +package com.susu.feature.loginsignup.signup + +import com.susu.core.model.Term +import com.susu.core.model.TermDetail +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState + +object TermEffect : SideEffect + +data class TermState( + val terms: List = emptyList(), + val currentTerm: TermDetail = TermDetail(0, "", false, ""), +): UiState diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt new file mode 100644 index 00000000..13f32331 --- /dev/null +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt @@ -0,0 +1,36 @@ +package com.susu.feature.loginsignup.signup + +import androidx.lifecycle.viewModelScope +import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.loginsignup.GetTermDetailUseCase +import com.susu.domain.usecase.loginsignup.GetTermsUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class TermViewModel @Inject constructor( + private val getTermsUseCase: GetTermsUseCase, + private val getTermDetailUseCase: GetTermDetailUseCase, +) : BaseViewModel(TermState()) { + + init { + viewModelScope.launch { + getTermsUseCase().onSuccess { + intent { copy(terms = it) } + }.onFailure { + // TODO: 실패 + } + } + } + + fun updateCurrentTerm(termId: Int) { + viewModelScope.launch { + getTermDetailUseCase(termId).onSuccess { + intent { copy(currentTerm = it) } + }.onFailure { + // TODO: 실패 + } + } + } +} From 8d1c5632972fe8be52fc45f5435b17d7adf309b5 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 20:13:09 +0900 Subject: [PATCH 06/31] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A6=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../loginsignup/signup/SignUpContract.kt | 1 + .../loginsignup/signup/SignUpScreen.kt | 18 +++++-- .../loginsignup/signup/SignUpViewModel.kt | 9 +++- .../loginsignup/signup/content/NameContent.kt | 52 +++++++++++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index 1e855008..d3e6d216 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -13,6 +13,7 @@ data class SignUpState( val currentStep: SignUpStep = SignUpStep.TERMS, val agreedTerms: List = emptyList(), val name: String = "", + val isNameValid: Boolean = true, val gender: Gender = Gender.NONE, val birth: Int = 1930, ) : UiState diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 732d2b75..092e79f7 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -26,6 +26,7 @@ import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.loginsignup.signup.content.NameContent import com.susu.feature.loginsignup.signup.content.TermsContent @Composable @@ -51,9 +52,9 @@ fun SignUpRoute( SignUpScreen( uiState = uiState, isNextStepActive = when (uiState.currentStep) { - SignUpStep.TERMS -> uiState.agreedTerms.containsAll(listOf(1, 2)) + SignUpStep.TERMS -> uiState.agreedTerms.containsAll(termState.terms.map { it.id }) SignUpStep.TERM_DETAIL -> true - SignUpStep.NAME -> true + SignUpStep.NAME -> uiState.isNameValid && uiState.name.isNotEmpty() SignUpStep.ADDITIONAL -> true }, onPreviousPressed = viewModel::goPreviousStep, @@ -106,7 +107,14 @@ fun SignUpRoute( } SignUpStep.NAME -> { - Text(text = targetState.description) + NameContent( + modifier = Modifier.fillMaxSize(), + description = targetState.description, + text = uiState.name, + isError = uiState.isNameValid.not(), + onTextChange = viewModel::updateName, + onClickClearIcon = { viewModel.updateName("") }, + ) } SignUpStep.ADDITIONAL -> { @@ -152,8 +160,8 @@ fun SignUpScreen( onClick = onPreviousPressed, ) }, - currentStep = SignUpStep.entries.indexOf(uiState.currentStep), - entireStep = SignUpStep.entries.size - 1, + currentStep = SignUpStep.entries.indexOf(uiState.currentStep) - 1, + entireStep = SignUpStep.entries.size - 2, ) } content() diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index 890412bc..19a40689 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -15,7 +15,10 @@ class SignUpViewModel @Inject constructor( ) : BaseViewModel(SignUpState()) { fun updateName(name: String) { - intent { copy(name = name) } + val trimmedName = name.trim() + val slicedName = if (trimmedName.length > 20) trimmedName.slice(0 until 20) else trimmedName + + intent { copy(name = slicedName, isNameValid = nameRegex.matches(slicedName)) } } fun updateGender(gender: Gender) { @@ -86,4 +89,8 @@ class SignUpViewModel @Inject constructor( } } } + + companion object { + private val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") + } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt new file mode 100644 index 00000000..fcc5f024 --- /dev/null +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt @@ -0,0 +1,52 @@ +package com.susu.feature.loginsignup.signup.content + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.component.textfield.SusuUnderlineTextField +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.loginsignup.signup.SignUpStep + +@Composable +fun NameContent( + modifier: Modifier = Modifier, + description: String = "", + text: String = "", + isError: Boolean = false, + onTextChange: (String) -> Unit = {}, + onClickClearIcon: () -> Unit = {}, +) { + Column( + modifier = modifier.padding(horizontal = 16.dp, vertical = 24.dp), + ) { + Text(text = description, style = SusuTheme.typography.title_m) + Spacer(modifier = Modifier.height(32.dp)) + SusuUnderlineTextField( + text = text, + placeholder = "김수수", + isError = isError, + lengthLimit = 10, + description = if (isError && text.isNotEmpty()) "한글과 영문 10자 이내로 입력해주세요" else null, + onTextChange = onTextChange, + onClickClearIcon = onClickClearIcon, + ) + } +} + +@Preview(showSystemUi = true) +@Composable +fun NameContentPreview() { + SusuTheme { + NameContent( + modifier = Modifier.fillMaxSize(), + description = SignUpStep.NAME.description, + ) + } +} From d160a978c0db69872d9d78bb39d877ee2b9c19b6 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 20:32:24 +0900 Subject: [PATCH 07/31] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=9E=85=EB=A0=A5=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../loginsignup/signup/SignUpContract.kt | 2 +- .../loginsignup/signup/SignUpScreen.kt | 175 ++++++++++-------- .../signup/content/AdditionalContent.kt | 88 +++++++++ 3 files changed, 191 insertions(+), 74 deletions(-) create mode 100644 feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index d3e6d216..3334b140 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -15,7 +15,7 @@ data class SignUpState( val name: String = "", val isNameValid: Boolean = true, val gender: Gender = Gender.NONE, - val birth: Int = 1930, + val birth: Int = -1, ) : UiState enum class SignUpStep( diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 092e79f7..4cefb01d 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -4,15 +4,20 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text 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 +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.tooling.preview.Preview @@ -22,13 +27,16 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.susu.core.designsystem.component.appbar.SusuDefaultAppBar import com.susu.core.designsystem.component.appbar.SusuProgressAppBar import com.susu.core.designsystem.component.appbar.icon.BackIcon +import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuYearPickerBottomSheet import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.loginsignup.signup.content.AdditionalContent import com.susu.feature.loginsignup.signup.content.NameContent import com.susu.feature.loginsignup.signup.content.TermsContent +@OptIn(ExperimentalMaterial3Api::class) @Composable fun SignUpRoute( viewModel: SignUpViewModel = hiltViewModel(), @@ -39,6 +47,8 @@ fun SignUpRoute( val uiState: SignUpState by viewModel.uiState.collectAsStateWithLifecycle() val termState: TermState by termViewModel.uiState.collectAsStateWithLifecycle() + var showDatePicker by remember { mutableStateOf(false) } + LaunchedEffect(key1 = viewModel.sideEffect) { viewModel.sideEffect.collect { sideEffect -> when (sideEffect) { @@ -49,87 +59,106 @@ fun SignUpRoute( } } - SignUpScreen( - uiState = uiState, - isNextStepActive = when (uiState.currentStep) { - SignUpStep.TERMS -> uiState.agreedTerms.containsAll(termState.terms.map { it.id }) - SignUpStep.TERM_DETAIL -> true - SignUpStep.NAME -> uiState.isNameValid && uiState.name.isNotEmpty() - SignUpStep.ADDITIONAL -> true - }, - onPreviousPressed = viewModel::goPreviousStep, - onNextPressed = { - if (uiState.currentStep == SignUpStep.TERM_DETAIL) { - viewModel.agreeTerm(termState.currentTerm.id) - } - viewModel.goNextStep() - }, - ) { - AnimatedContent( - modifier = Modifier.weight(1f), - targetState = uiState.currentStep, - label = "SignUpContent", - transitionSpec = { - val direction = if (targetState.ordinal > initialState.ordinal) - AnimatedContentTransitionScope.SlideDirection.Left - else AnimatedContentTransitionScope.SlideDirection.Right - slideIntoContainer( - towards = direction, - animationSpec = tween(500), - ) togetherWith slideOutOfContainer( - towards = direction, - animationSpec = tween(500), - ) + Box(modifier = Modifier.fillMaxSize()) { + SignUpScreen( + uiState = uiState, + isNextStepActive = when (uiState.currentStep) { + SignUpStep.TERMS -> uiState.agreedTerms.containsAll(termState.terms.map { it.id }) + SignUpStep.TERM_DETAIL -> true + SignUpStep.NAME -> uiState.isNameValid && uiState.name.isNotEmpty() + SignUpStep.ADDITIONAL -> true }, - ) { targetState -> - when (targetState) { - SignUpStep.TERMS -> { - TermsContent( - modifier = Modifier.fillMaxSize(), - descriptionText = targetState.description, - terms = termState.terms, - agreedTerms = uiState.agreedTerms, - onDetailClick = { - termViewModel.updateCurrentTerm(it) - viewModel.goTermDetail() - }, - onSelectAll = { agree -> - if (agree) { - viewModel.agreeAllTerms(termState.terms.map { it.id }) - } else { - viewModel.disagreeAllTerms() - } - }, - onTermChecked = { agree, id -> - if (agree) viewModel.agreeTerm(id) else viewModel.disagreeTerm(id) - }, - ) + onPreviousPressed = viewModel::goPreviousStep, + onNextPressed = { + if (uiState.currentStep == SignUpStep.TERM_DETAIL) { + viewModel.agreeTerm(termState.currentTerm.id) } - - SignUpStep.NAME -> { - NameContent( - modifier = Modifier.fillMaxSize(), - description = targetState.description, - text = uiState.name, - isError = uiState.isNameValid.not(), - onTextChange = viewModel::updateName, - onClickClearIcon = { viewModel.updateName("") }, + viewModel.goNextStep() + }, + ) { + AnimatedContent( + modifier = Modifier.weight(1f), + targetState = uiState.currentStep, + label = "SignUpContent", + transitionSpec = { + val direction = if (targetState.ordinal > initialState.ordinal) + AnimatedContentTransitionScope.SlideDirection.Left + else AnimatedContentTransitionScope.SlideDirection.Right + slideIntoContainer( + towards = direction, + animationSpec = tween(500), + ) togetherWith slideOutOfContainer( + towards = direction, + animationSpec = tween(500), ) - } + }, + ) { targetState -> + when (targetState) { + SignUpStep.TERMS -> { + TermsContent( + modifier = Modifier.fillMaxSize(), + descriptionText = targetState.description, + terms = termState.terms, + agreedTerms = uiState.agreedTerms, + onDetailClick = { + termViewModel.updateCurrentTerm(it) + viewModel.goTermDetail() + }, + onSelectAll = { agree -> + if (agree) { + viewModel.agreeAllTerms(termState.terms.map { it.id }) + } else { + viewModel.disagreeAllTerms() + } + }, + onTermChecked = { agree, id -> + if (agree) viewModel.agreeTerm(id) else viewModel.disagreeTerm(id) + }, + ) + } - SignUpStep.ADDITIONAL -> { - Text(text = targetState.description) - } + SignUpStep.NAME -> { + NameContent( + modifier = Modifier.fillMaxSize(), + description = targetState.description, + text = uiState.name, + isError = uiState.isNameValid.not(), + onTextChange = viewModel::updateName, + onClickClearIcon = { viewModel.updateName("") }, + ) + } - SignUpStep.TERM_DETAIL -> { - Text( - modifier = Modifier.fillMaxSize().padding(16.dp), - text = termState.currentTerm.description, - style = SusuTheme.typography.text_xxxs, - ) + SignUpStep.ADDITIONAL -> { + AdditionalContent( + modifier = Modifier.fillMaxSize(), + description = targetState.description, + selectedGender = uiState.gender, + selectedYear = uiState.birth, + onGenderSelect = viewModel::updateGender, + onYearClick = { showDatePicker = true }, + ) + } + + SignUpStep.TERM_DETAIL -> { + Text( + modifier = Modifier.fillMaxSize().padding(16.dp), + text = termState.currentTerm.description, + style = SusuTheme.typography.text_xxxs, + ) + } } } } + + if (showDatePicker) { + SusuYearPickerBottomSheet( + maximumContainerHeight = 322.dp, + onDismissRequest = { + viewModel.updateBirth(it) + showDatePicker = false + } + ) + } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt new file mode 100644 index 00000000..178165d7 --- /dev/null +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt @@ -0,0 +1,88 @@ +package com.susu.feature.loginsignup.signup.content + +import androidx.compose.foundation.layout.Arrangement +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.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.susu.core.designsystem.component.button.GhostButtonColor +import com.susu.core.designsystem.component.button.MediumButtonStyle +import com.susu.core.designsystem.component.button.SusuGhostButton +import com.susu.core.designsystem.theme.Gray60 +import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.loginsignup.signup.Gender +import com.susu.feature.loginsignup.signup.SignUpStep +import java.time.LocalDate + +@Composable +fun AdditionalContent( + modifier: Modifier = Modifier, + description: String = "", + selectedGender: Gender = Gender.NONE, + selectedYear: Int = -1, + onGenderSelect: (Gender) -> Unit = {}, + onYearClick: () -> Unit = {} +) { + Column( + modifier = modifier.padding(horizontal = 16.dp, vertical = 24.dp), + ) { + Text(text = description, style = SusuTheme.typography.title_m) + Spacer(modifier = Modifier.height(32.dp)) + Text(text = "성별", style = SusuTheme.typography.title_xxxs, color = Gray60) + Spacer(modifier = Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + SusuGhostButton( + modifier = Modifier.weight(1f), + text = "남성", + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + isClickable = true, + isActive = selectedGender == Gender.MALE, + onClick = { onGenderSelect(Gender.MALE) } + ) + SusuGhostButton( + modifier = Modifier.weight(1f), + text = "여성", + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + isClickable = true, + isActive = selectedGender == Gender.FEMALE, + onClick = { onGenderSelect(Gender.FEMALE) } + ) + } + Spacer(modifier = Modifier.height(24.dp)) + Text(text = "출생년도", style = SusuTheme.typography.title_xxxs, color = Gray60) + SusuGhostButton( + modifier = Modifier.fillMaxWidth(), + text = if (selectedYear < 0) LocalDate.now().year.toString() else selectedYear.toString(), + color = GhostButtonColor.Black, + style = MediumButtonStyle.height60, + isClickable = true, + isActive = selectedYear > 0, + onClick = onYearClick + ) + } +} + +@Preview(showSystemUi = true) +@Composable +fun AdditionalContentPreview() { + SusuTheme { + AdditionalContent( + modifier = Modifier.fillMaxSize(), + description = SignUpStep.ADDITIONAL.description, + selectedGender = Gender.MALE, + ) + } +} From 94edf1fa48370d833a97e594263b2eab7942d842 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 20:36:45 +0900 Subject: [PATCH 08/31] =?UTF-8?q?chore:=20SusuSpacing=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../susu/feature/loginsignup/signup/SignUpScreen.kt | 4 ++-- .../loginsignup/signup/content/AdditionalContent.kt | 8 ++++---- .../loginsignup/signup/content/NameContent.kt | 5 ++--- .../loginsignup/signup/content/TermsContent.kt | 12 ++++++------ 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 4cefb01d..a85a47a6 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -141,7 +141,7 @@ fun SignUpRoute( SignUpStep.TERM_DETAIL -> { Text( - modifier = Modifier.fillMaxSize().padding(16.dp), + modifier = Modifier.fillMaxSize().padding(SusuTheme.spacing.spacing_m), text = termState.currentTerm.description, style = SusuTheme.typography.text_xxxs, ) @@ -156,7 +156,7 @@ fun SignUpRoute( onDismissRequest = { viewModel.updateBirth(it) showDatePicker = false - } + }, ) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt index 178165d7..f885c717 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt @@ -35,12 +35,12 @@ fun AdditionalContent( modifier = modifier.padding(horizontal = 16.dp, vertical = 24.dp), ) { Text(text = description, style = SusuTheme.typography.title_m) - Spacer(modifier = Modifier.height(32.dp)) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxl)) Text(text = "성별", style = SusuTheme.typography.title_xxxs, color = Gray60) - Spacer(modifier = Modifier.height(8.dp)) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxs)) Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(SusuTheme.spacing.spacing_xxs), ) { SusuGhostButton( modifier = Modifier.weight(1f), @@ -61,7 +61,7 @@ fun AdditionalContent( onClick = { onGenderSelect(Gender.FEMALE) } ) } - Spacer(modifier = Modifier.height(24.dp)) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xl)) Text(text = "출생년도", style = SusuTheme.typography.title_xxxs, color = Gray60) SusuGhostButton( modifier = Modifier.fillMaxWidth(), diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt index fcc5f024..0468e7e4 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt @@ -9,7 +9,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.textfield.SusuUnderlineTextField import com.susu.core.designsystem.theme.SusuTheme import com.susu.feature.loginsignup.signup.SignUpStep @@ -24,10 +23,10 @@ fun NameContent( onClickClearIcon: () -> Unit = {}, ) { Column( - modifier = modifier.padding(horizontal = 16.dp, vertical = 24.dp), + modifier = modifier.padding(horizontal = SusuTheme.spacing.spacing_m, vertical = SusuTheme.spacing.spacing_xl), ) { Text(text = description, style = SusuTheme.typography.title_m) - Spacer(modifier = Modifier.height(32.dp)) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxl)) SusuUnderlineTextField( text = text, placeholder = "김수수", diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt index 3ef4eb4b..d9730371 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt @@ -46,13 +46,13 @@ fun TermsContent( onTermChecked: (agree: Boolean, id: Int) -> Unit = { _, _ -> }, ) { Column( - modifier = modifier.padding(16.dp), + modifier = modifier.padding(SusuTheme.spacing.spacing_m), ) { Text( text = descriptionText, style = SusuTheme.typography.title_m, ) - Spacer(modifier = Modifier.height(24.dp)) + Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xl)) TermListItem( title = "전체 동의하기", checked = agreedTerms.containsAll(terms.map { it.id }), @@ -89,14 +89,14 @@ fun TermListItem( onDetailClick: () -> Unit = {}, ) { Row( - modifier = modifier.padding(vertical = 16.dp), + modifier = modifier.padding(vertical = SusuTheme.spacing.spacing_m), verticalAlignment = Alignment.CenterVertically, ) { TermCheckCircle(isChecked = checked, onCheckedChange = onCheckClick) - Spacer(modifier = Modifier.width(16.dp)) + Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_m)) if (isEssential) { SusuBadge(color = BadgeColor.Blue60, text = "필수", padding = BadgeStyle.smallBadge) - Spacer(modifier = Modifier.width(8.dp)) + Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_xxs)) } Text( modifier = Modifier.weight(1f), @@ -104,7 +104,7 @@ fun TermListItem( style = SusuTheme.typography.title_xxs, ) if (canRead) { - Spacer(modifier = Modifier.width(16.dp)) + Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_m)) Image( modifier = Modifier .size(20.dp) From 4b57985f5edda9533b7577c1c46358b48dcb29a6 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 20:48:39 +0900 Subject: [PATCH 09/31] =?UTF-8?q?chore:=20string=20resource=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ui/src/main/res/values/strings.xml | 4 +++ .../loginsignup/signup/SignUpContract.kt | 32 ++++++++++--------- .../loginsignup/signup/SignUpScreen.kt | 15 +++++---- .../signup/content/AdditionalContent.kt | 13 ++++---- .../loginsignup/signup/content/NameContent.kt | 7 ++-- .../signup/content/TermsContent.kt | 9 ++++-- .../src/main/res/values/strings.xml | 10 ++++++ 7 files changed, 58 insertions(+), 32 deletions(-) diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 2d6e4333..6d8b786d 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -18,4 +18,8 @@ 카테고리 날짜 더하기 버튼 + 남성 + 여성 + 출생년도 + 다음 diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index 3334b140..477f4f03 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -1,7 +1,9 @@ package com.susu.feature.loginsignup.signup +import androidx.annotation.StringRes import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState +import com.susu.feature.loginsignup.R sealed class SignUpEffect : SideEffect { data object NavigateToLogin : SignUpEffect() @@ -19,29 +21,29 @@ data class SignUpState( ) : UiState enum class SignUpStep( - val appBarTitle: String, - val description: String, - val bottomButtonText: String, + @StringRes val appBarTitle: Int?, + @StringRes val description: Int?, + @StringRes val bottomButtonText: Int, ) { TERMS( - appBarTitle = "약관 동의", - description = "서비스 약관을 위해\n약관에 동의해주세요", - bottomButtonText = "다음", + appBarTitle = R.string.signup_term_title, + description = R.string.signup_term_description, + bottomButtonText = com.susu.core.ui.R.string.word_next, ), TERM_DETAIL( - appBarTitle = "서비스 이용 약관", - description = "", - bottomButtonText = "동의하기", + appBarTitle = R.string.signup_term_detail_title, + description = null, + bottomButtonText = R.string.signup_term_agree, ), NAME( - appBarTitle = "", - description = "반가워요!\n이름을 알려주세요", - bottomButtonText = "다음", + appBarTitle = null, + description = R.string.signup_name_description, + bottomButtonText = com.susu.core.ui.R.string.word_next, ), ADDITIONAL( - appBarTitle = "", - description = "아래 정보들을 알려주시면\n통계를 알려드릴 수 있어요", - bottomButtonText = "다음", + appBarTitle = null, + description = R.string.signup_additional_description, + bottomButtonText = com.susu.core.ui.R.string.word_next, ), } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index a85a47a6..a96d0ee3 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel @@ -97,7 +98,7 @@ fun SignUpRoute( SignUpStep.TERMS -> { TermsContent( modifier = Modifier.fillMaxSize(), - descriptionText = targetState.description, + descriptionText = targetState.description?.let { stringResource(id = it) } ?: "", terms = termState.terms, agreedTerms = uiState.agreedTerms, onDetailClick = { @@ -120,7 +121,7 @@ fun SignUpRoute( SignUpStep.NAME -> { NameContent( modifier = Modifier.fillMaxSize(), - description = targetState.description, + description = targetState.description?.let { stringResource(id = it) } ?: "", text = uiState.name, isError = uiState.isNameValid.not(), onTextChange = viewModel::updateName, @@ -131,7 +132,7 @@ fun SignUpRoute( SignUpStep.ADDITIONAL -> { AdditionalContent( modifier = Modifier.fillMaxSize(), - description = targetState.description, + description = targetState.description?.let { stringResource(id = it) } ?: "", selectedGender = uiState.gender, selectedYear = uiState.birth, onGenderSelect = viewModel::updateGender, @@ -141,7 +142,9 @@ fun SignUpRoute( SignUpStep.TERM_DETAIL -> { Text( - modifier = Modifier.fillMaxSize().padding(SusuTheme.spacing.spacing_m), + modifier = Modifier + .fillMaxSize() + .padding(SusuTheme.spacing.spacing_m), text = termState.currentTerm.description, style = SusuTheme.typography.text_xxxs, ) @@ -180,7 +183,7 @@ fun SignUpScreen( onClick = onPreviousPressed, ) }, - title = uiState.currentStep.appBarTitle, + title = uiState.currentStep.appBarTitle?.let { stringResource(id = it) } ?: "", ) } else { SusuProgressAppBar( @@ -199,7 +202,7 @@ fun SignUpScreen( shape = RectangleShape, color = FilledButtonColor.Black, style = MediumButtonStyle.height60, - text = uiState.currentStep.bottomButtonText, + text = stringResource(id = uiState.currentStep.bottomButtonText), isActive = isNextStepActive, onClick = onNextPressed, ) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt index f885c717..10cca5ec 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.button.GhostButtonColor @@ -18,6 +19,7 @@ import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuGhostButton import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.loginsignup.R import com.susu.feature.loginsignup.signup.Gender import com.susu.feature.loginsignup.signup.SignUpStep import java.time.LocalDate @@ -44,25 +46,25 @@ fun AdditionalContent( ) { SusuGhostButton( modifier = Modifier.weight(1f), - text = "남성", + text = stringResource(com.susu.core.ui.R.string.word_male), color = GhostButtonColor.Black, style = MediumButtonStyle.height60, isClickable = true, isActive = selectedGender == Gender.MALE, - onClick = { onGenderSelect(Gender.MALE) } + onClick = { onGenderSelect(Gender.MALE) }, ) SusuGhostButton( modifier = Modifier.weight(1f), - text = "여성", + text = stringResource(com.susu.core.ui.R.string.word_female), color = GhostButtonColor.Black, style = MediumButtonStyle.height60, isClickable = true, isActive = selectedGender == Gender.FEMALE, - onClick = { onGenderSelect(Gender.FEMALE) } + onClick = { onGenderSelect(Gender.FEMALE) }, ) } Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xl)) - Text(text = "출생년도", style = SusuTheme.typography.title_xxxs, color = Gray60) + Text(text = stringResource(com.susu.core.ui.R.string.word_birth), style = SusuTheme.typography.title_xxxs, color = Gray60) SusuGhostButton( modifier = Modifier.fillMaxWidth(), text = if (selectedYear < 0) LocalDate.now().year.toString() else selectedYear.toString(), @@ -81,7 +83,6 @@ fun AdditionalContentPreview() { SusuTheme { AdditionalContent( modifier = Modifier.fillMaxSize(), - description = SignUpStep.ADDITIONAL.description, selectedGender = Gender.MALE, ) } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt index 0468e7e4..2241db1e 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt @@ -8,9 +8,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.susu.core.designsystem.component.textfield.SusuUnderlineTextField import com.susu.core.designsystem.theme.SusuTheme +import com.susu.feature.loginsignup.R import com.susu.feature.loginsignup.signup.SignUpStep @Composable @@ -29,10 +31,10 @@ fun NameContent( Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xxl)) SusuUnderlineTextField( text = text, - placeholder = "김수수", + placeholder = stringResource(R.string.signup_name_sample), isError = isError, lengthLimit = 10, - description = if (isError && text.isNotEmpty()) "한글과 영문 10자 이내로 입력해주세요" else null, + description = if (isError && text.isNotEmpty()) stringResource(R.string.signup_name_limitation) else null, onTextChange = onTextChange, onClickClearIcon = onClickClearIcon, ) @@ -45,7 +47,6 @@ fun NameContentPreview() { SusuTheme { NameContent( modifier = Modifier.fillMaxSize(), - description = SignUpStep.NAME.description, ) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt index d9730371..5d993083 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.susu.core.designsystem.component.badge.BadgeColor @@ -54,7 +55,7 @@ fun TermsContent( ) Spacer(modifier = Modifier.height(SusuTheme.spacing.spacing_xl)) TermListItem( - title = "전체 동의하기", + title = stringResource(com.susu.feature.loginsignup.R.string.signup_term_agree_all), checked = agreedTerms.containsAll(terms.map { it.id }), isEssential = false, canRead = false, @@ -95,7 +96,11 @@ fun TermListItem( TermCheckCircle(isChecked = checked, onCheckedChange = onCheckClick) Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_m)) if (isEssential) { - SusuBadge(color = BadgeColor.Blue60, text = "필수", padding = BadgeStyle.smallBadge) + SusuBadge( + color = BadgeColor.Blue60, + text = stringResource(com.susu.feature.loginsignup.R.string.signup_essential), + padding = BadgeStyle.smallBadge, + ) Spacer(modifier = Modifier.width(SusuTheme.spacing.spacing_xxs)) } Text( diff --git a/feature/loginsignup/src/main/res/values/strings.xml b/feature/loginsignup/src/main/res/values/strings.xml index 1c37b08c..5ed3527d 100644 --- a/feature/loginsignup/src/main/res/values/strings.xml +++ b/feature/loginsignup/src/main/res/values/strings.xml @@ -15,4 +15,14 @@ "은 " 얼마가 적당하다 고\n생각하시나요 + 김수수 + 한글과 영문 10자 이내로 입력해주세요 + 전체 동의하기 + 필수 + 약관 동의 + 서비스 약관을 위해\n약관에 동의해주세요 + 서비스 이용 약관 + 동의하기 + 반가워요!\n이름을 알려주세요 + 아래 정보들을 알려주시면\n통계를 알려드릴 수 있어요 From 662803da355c0b4eb4d4a37ef0187165f51a9b99 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 20:53:21 +0900 Subject: [PATCH 10/31] =?UTF-8?q?feat:=20Loading=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/feature/loginsignup/signup/SignUpContract.kt | 1 + .../com/susu/feature/loginsignup/signup/SignUpScreen.kt | 5 +++++ .../susu/feature/loginsignup/signup/SignUpViewModel.kt | 2 ++ .../com/susu/feature/loginsignup/signup/TermContract.kt | 3 ++- .../com/susu/feature/loginsignup/signup/TermViewModel.kt | 8 ++++++-- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index 477f4f03..a08127a4 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -12,6 +12,7 @@ sealed class SignUpEffect : SideEffect { } data class SignUpState( + val isLoading: Boolean = false, val currentStep: SignUpStep = SignUpStep.TERMS, val agreedTerms: List = emptyList(), val name: String = "", diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index a96d0ee3..0243da95 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -32,6 +32,7 @@ import com.susu.core.designsystem.component.bottomsheet.datepicker.SusuYearPicke import com.susu.core.designsystem.component.button.FilledButtonColor import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton +import com.susu.core.designsystem.component.screen.LoadingScreen import com.susu.core.designsystem.theme.SusuTheme import com.susu.feature.loginsignup.signup.content.AdditionalContent import com.susu.feature.loginsignup.signup.content.NameContent @@ -162,6 +163,10 @@ fun SignUpRoute( }, ) } + + if (uiState.isLoading || termState.isLoading) { + LoadingScreen(modifier = Modifier.fillMaxSize()) + } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index 19a40689..adfc99cb 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -70,6 +70,7 @@ class SignUpViewModel @Inject constructor( private fun signUp() { KakaoLoginHelper.getAccessToken { oauthAccessToken -> viewModelScope.launch { + intent { copy(isLoading = true) } if (oauthAccessToken != null) { signUpUseCase( oauthAccessToken = oauthAccessToken, @@ -86,6 +87,7 @@ class SignUpViewModel @Inject constructor( } else { postSideEffect(SignUpEffect.ShowToast("카카오톡 로그인 에러 발생")) } + intent { copy(isLoading = false) } } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt index 85a003c6..7780ac75 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt @@ -8,6 +8,7 @@ import com.susu.core.ui.base.UiState object TermEffect : SideEffect data class TermState( + val isLoading: Boolean = false, val terms: List = emptyList(), val currentTerm: TermDetail = TermDetail(0, "", false, ""), -): UiState +) : UiState diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt index 13f32331..2a6a8ab5 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt @@ -16,20 +16,24 @@ class TermViewModel @Inject constructor( init { viewModelScope.launch { + intent { copy(isLoading = true) } getTermsUseCase().onSuccess { - intent { copy(terms = it) } + intent { copy(terms = it, isLoading = false) } }.onFailure { // TODO: 실패 + intent { copy(isLoading = false) } } } } fun updateCurrentTerm(termId: Int) { viewModelScope.launch { + intent { copy(isLoading = true) } getTermDetailUseCase(termId).onSuccess { - intent { copy(currentTerm = it) } + intent { copy(currentTerm = it, isLoading = false) } }.onFailure { // TODO: 실패 + intent { copy(isLoading = false) } } } } From 36d079d2ded14f284b810bf87fdffbb0105c192b Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 20:58:18 +0900 Subject: [PATCH 11/31] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=20=EC=8B=9C=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/feature/loginsignup/signup/SignUpContract.kt | 8 ++++---- .../com/susu/feature/loginsignup/signup/SignUpScreen.kt | 5 ++++- .../com/susu/feature/loginsignup/signup/TermContract.kt | 4 +++- .../com/susu/feature/loginsignup/signup/TermViewModel.kt | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index a08127a4..de2c83bd 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -5,10 +5,10 @@ import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState import com.susu.feature.loginsignup.R -sealed class SignUpEffect : SideEffect { - data object NavigateToLogin : SignUpEffect() - data object NavigateToReceived : SignUpEffect() - data class ShowToast(val msg: String) : SignUpEffect() +sealed interface SignUpEffect : SideEffect { + data object NavigateToLogin : SignUpEffect + data object NavigateToReceived : SignUpEffect + data class ShowToast(val msg: String) : SignUpEffect } data class SignUpState( diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 0243da95..49619c6a 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -1,5 +1,6 @@ package com.susu.feature.loginsignup.signup +import android.widget.Toast import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween @@ -20,6 +21,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -46,6 +48,7 @@ fun SignUpRoute( navigateToReceived: () -> Unit, navigateToLogin: () -> Unit, ) { + val context = LocalContext.current val uiState: SignUpState by viewModel.uiState.collectAsStateWithLifecycle() val termState: TermState by termViewModel.uiState.collectAsStateWithLifecycle() @@ -56,7 +59,7 @@ fun SignUpRoute( when (sideEffect) { SignUpEffect.NavigateToLogin -> navigateToLogin() SignUpEffect.NavigateToReceived -> navigateToReceived() - is SignUpEffect.ShowToast -> {} + is SignUpEffect.ShowToast -> Toast.makeText(context, sideEffect.msg, Toast.LENGTH_SHORT).show() } } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt index 7780ac75..c832749b 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermContract.kt @@ -5,7 +5,9 @@ import com.susu.core.model.TermDetail import com.susu.core.ui.base.SideEffect import com.susu.core.ui.base.UiState -object TermEffect : SideEffect +sealed interface TermEffect : SideEffect { + data class ShowToast(val msg: String) : TermEffect +} data class TermState( val isLoading: Boolean = false, diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt index 2a6a8ab5..e3867d08 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt @@ -20,7 +20,7 @@ class TermViewModel @Inject constructor( getTermsUseCase().onSuccess { intent { copy(terms = it, isLoading = false) } }.onFailure { - // TODO: 실패 + postSideEffect(TermEffect.ShowToast(it.message ?: "약관을 불러오지 못했어요")) intent { copy(isLoading = false) } } } @@ -32,7 +32,7 @@ class TermViewModel @Inject constructor( getTermDetailUseCase(termId).onSuccess { intent { copy(currentTerm = it, isLoading = false) } }.onFailure { - // TODO: 실패 + postSideEffect(TermEffect.ShowToast(it.message ?: "약관 내용을 불러오지 못했어요")) intent { copy(isLoading = false) } } } From 1738e9cafd52a37578efce104bdc2b5ba33ad630 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 21:08:21 +0900 Subject: [PATCH 12/31] =?UTF-8?q?chore:=20=EC=B6=9C=EC=83=9D=EB=85=84?= =?UTF-8?q?=EB=8F=84=20=EC=84=A0=ED=83=9D=20=EB=B2=84=ED=8A=BC=EC=97=90=20?= =?UTF-8?q?'=EB=85=84'=20=EB=B6=99=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../loginsignup/signup/content/AdditionalContent.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt index 10cca5ec..05094a97 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/AdditionalContent.kt @@ -19,9 +19,7 @@ import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuGhostButton import com.susu.core.designsystem.theme.Gray60 import com.susu.core.designsystem.theme.SusuTheme -import com.susu.feature.loginsignup.R import com.susu.feature.loginsignup.signup.Gender -import com.susu.feature.loginsignup.signup.SignUpStep import java.time.LocalDate @Composable @@ -31,7 +29,7 @@ fun AdditionalContent( selectedGender: Gender = Gender.NONE, selectedYear: Int = -1, onGenderSelect: (Gender) -> Unit = {}, - onYearClick: () -> Unit = {} + onYearClick: () -> Unit = {}, ) { Column( modifier = modifier.padding(horizontal = 16.dp, vertical = 24.dp), @@ -67,12 +65,15 @@ fun AdditionalContent( Text(text = stringResource(com.susu.core.ui.R.string.word_birth), style = SusuTheme.typography.title_xxxs, color = Gray60) SusuGhostButton( modifier = Modifier.fillMaxWidth(), - text = if (selectedYear < 0) LocalDate.now().year.toString() else selectedYear.toString(), + text = stringResource( + id = com.susu.core.designsystem.R.string.word_year_format, + if (selectedYear < 0) LocalDate.now().year else selectedYear, + ), color = GhostButtonColor.Black, style = MediumButtonStyle.height60, isClickable = true, isActive = selectedYear > 0, - onClick = onYearClick + onClick = onYearClick, ) } } From ee159f8f67e90318c70f0042a332ce3e8b65c35f Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 21:20:51 +0900 Subject: [PATCH 13/31] =?UTF-8?q?feat:=20imePadding=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 했는데 왜 안올라오지.. --- .../loginsignup/navigation/LoginSignupNavigation.kt | 3 +++ .../com/susu/feature/loginsignup/signup/SignUpScreen.kt | 7 +++++-- .../src/main/java/com/susu/feature/navigator/MainScreen.kt | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt index ce120fe1..782b984d 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt @@ -1,5 +1,6 @@ package com.susu.feature.loginsignup.navigation +import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions @@ -14,6 +15,7 @@ fun NavController.navigateLoginSignup(navOptions: NavOptions) { } fun NavGraphBuilder.loginSignupNavGraph( + padding: PaddingValues, navController: NavController, navigateToReceived: () -> Unit, ) { @@ -46,6 +48,7 @@ fun NavGraphBuilder.loginSignupNavGraph( } composable(route = LoginSignupRoute.Parent.SignUp.route) { SignUpRoute( + padding = padding, navigateToReceived = navigateToReceived, navigateToLogin = { navController.navigate(LoginSignupRoute.Parent.Login.route) { diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 49619c6a..7a75c21c 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -43,6 +44,7 @@ import com.susu.feature.loginsignup.signup.content.TermsContent @OptIn(ExperimentalMaterial3Api::class) @Composable fun SignUpRoute( + padding: PaddingValues, viewModel: SignUpViewModel = hiltViewModel(), termViewModel: TermViewModel = hiltViewModel(), navigateToReceived: () -> Unit, @@ -64,7 +66,7 @@ fun SignUpRoute( } } - Box(modifier = Modifier.fillMaxSize()) { + Box(modifier = Modifier.fillMaxSize().padding(padding)) { SignUpScreen( uiState = uiState, isNextStepActive = when (uiState.currentStep) { @@ -175,6 +177,7 @@ fun SignUpRoute( @Composable fun SignUpScreen( + modifier: Modifier = Modifier, uiState: SignUpState = SignUpState(), isNextStepActive: Boolean = false, onPreviousPressed: () -> Unit = {}, @@ -182,7 +185,7 @@ fun SignUpScreen( content: @Composable ColumnScope.() -> Unit = {}, ) { Column( - modifier = Modifier.fillMaxSize(), + modifier = modifier.fillMaxSize(), ) { if (uiState.currentStep == SignUpStep.TERMS || uiState.currentStep == SignUpStep.TERM_DETAIL) { SusuDefaultAppBar( diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index cdd24ae2..bbb3e5d5 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -55,6 +55,7 @@ internal fun MainScreen( loginSignupNavGraph( navController = navigator.navController, navigateToReceived = navigator::navigateSent, + padding = innerPadding ) sentNavGraph( From 6821103a512b22f2101f4b070072831d8251e0cb Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 21:21:44 +0900 Subject: [PATCH 14/31] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EA=B3=BC=EC=A0=95=EC=97=90=EC=84=9C=20backbutton?= =?UTF-8?q?=20=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/loginsignup/navigation/LoginSignupNavigation.kt | 2 +- .../java/com/susu/feature/loginsignup/signup/SignUpScreen.kt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt index 782b984d..f9031611 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt @@ -53,7 +53,7 @@ fun NavGraphBuilder.loginSignupNavGraph( navigateToLogin = { navController.navigate(LoginSignupRoute.Parent.Login.route) { popUpTo( - route = LoginSignupRoute.Parent.Vote.route, + route = LoginSignupRoute.Parent.SignUp.route, ) { inclusive = true } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 7a75c21c..54c3ec5d 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -1,6 +1,7 @@ package com.susu.feature.loginsignup.signup import android.widget.Toast +import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.core.tween @@ -56,6 +57,10 @@ fun SignUpRoute( var showDatePicker by remember { mutableStateOf(false) } + BackHandler { + viewModel.goPreviousStep() + } + LaunchedEffect(key1 = viewModel.sideEffect) { viewModel.sideEffect.collect { sideEffect -> when (sideEffect) { From 4f2e66d3836d880ccbf58841770ffdd2e011a422 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 21:30:35 +0900 Subject: [PATCH 15/31] =?UTF-8?q?fix:=20User=20=EC=88=98=EC=A0=95=EB=90=9C?= =?UTF-8?q?=20api=20=ED=98=95=EC=8B=9D=EC=97=90=20=EB=A7=9E=EA=B2=8C=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 --- core/model/src/main/java/com/susu/core/model/User.kt | 1 + .../java/com/susu/data/remote/model/request/UserRequest.kt | 2 ++ .../com/susu/feature/loginsignup/signup/SignUpViewModel.kt | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/model/src/main/java/com/susu/core/model/User.kt b/core/model/src/main/java/com/susu/core/model/User.kt index 30d34830..750b8e03 100644 --- a/core/model/src/main/java/com/susu/core/model/User.kt +++ b/core/model/src/main/java/com/susu/core/model/User.kt @@ -3,5 +3,6 @@ package com.susu.core.model data class User( val name: String, val gender: String, + val termAgreement: List, val birth: Int, ) diff --git a/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt index e2eee3af..2102fd94 100644 --- a/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt +++ b/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.Serializable data class UserRequest( val name: String, val gender: String, + val termAgreement: List, val birth: Int, ) @@ -14,4 +15,5 @@ fun User.toData() = UserRequest( name = name, gender = gender, birth = birth, + termAgreement = termAgreement, ) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index adfc99cb..8c3edb0c 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -16,7 +16,7 @@ class SignUpViewModel @Inject constructor( fun updateName(name: String) { val trimmedName = name.trim() - val slicedName = if (trimmedName.length > 20) trimmedName.slice(0 until 20) else trimmedName + val slicedName = if (trimmedName.length > 10) trimmedName.slice(0 until 10) else trimmedName intent { copy(name = slicedName, isNameValid = nameRegex.matches(slicedName)) } } @@ -78,6 +78,7 @@ class SignUpViewModel @Inject constructor( name = uiState.value.name, gender = uiState.value.gender.content, birth = uiState.value.birth, + termAgreement = uiState.value.agreedTerms ), ).onSuccess { postSideEffect(SignUpEffect.NavigateToReceived) From 800ec1e13a3acb2eae17c35e2cd437b8fd676d6d Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 21:32:19 +0900 Subject: [PATCH 16/31] =?UTF-8?q?fix:=20SignUpScreen=20=EC=96=B4=EC=83=89?= =?UTF-8?q?=ED=95=9C=20UI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로딩 인디케이터가 화면 가득 참, 다음 버튼이 비활성화 되어있어도 클릭 가능했음 --- .../java/com/susu/feature/loginsignup/signup/SignUpScreen.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 54c3ec5d..dddbd3e1 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.platform.LocalContext @@ -175,7 +176,7 @@ fun SignUpRoute( } if (uiState.isLoading || termState.isLoading) { - LoadingScreen(modifier = Modifier.fillMaxSize()) + LoadingScreen(modifier = Modifier.align(Alignment.Center)) } } } @@ -220,6 +221,7 @@ fun SignUpScreen( style = MediumButtonStyle.height60, text = stringResource(id = uiState.currentStep.bottomButtonText), isActive = isNextStepActive, + isClickable = isNextStepActive, onClick = onNextPressed, ) } From 13a7719128851590beba41505f700acf7ad892b7 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 22:20:45 +0900 Subject: [PATCH 17/31] =?UTF-8?q?fix:=20=ED=95=84=EC=88=98=20=EC=95=BD?= =?UTF-8?q?=EA=B4=80=EB=A7=8C=20=EB=AA=A8=EB=91=90=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=ED=95=98=EB=A9=B4=20=EB=B2=84=ED=8A=BC=EC=9D=B4=20=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/feature/loginsignup/signup/SignUpScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index dddbd3e1..51b275ee 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -76,7 +76,7 @@ fun SignUpRoute( SignUpScreen( uiState = uiState, isNextStepActive = when (uiState.currentStep) { - SignUpStep.TERMS -> uiState.agreedTerms.containsAll(termState.terms.map { it.id }) + SignUpStep.TERMS -> uiState.agreedTerms.containsAll(termState.terms.filter { it.isEssential }.map { it.id }) SignUpStep.TERM_DETAIL -> true SignUpStep.NAME -> uiState.isNameValid && uiState.name.isNotEmpty() SignUpStep.ADDITIONAL -> true From 51484b739c43dd1ecf33c807d1425abc15286667 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Thu, 11 Jan 2024 22:22:56 +0900 Subject: [PATCH 18/31] =?UTF-8?q?feat:=20=EC=84=B1=EB=B3=84,=20=EC=B6=9C?= =?UTF-8?q?=EC=83=9D=EB=85=84=EB=8F=84=20=EB=AF=B8=EC=84=A0=ED=83=9D=20->?= =?UTF-8?q?=20Null=EB=A1=9C=20=EC=A0=84=EC=86=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/susu/data/remote/model/request/UserRequest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt b/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt index 2102fd94..b212b35a 100644 --- a/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt +++ b/data/src/main/java/com/susu/data/remote/model/request/UserRequest.kt @@ -6,14 +6,14 @@ import kotlinx.serialization.Serializable @Serializable data class UserRequest( val name: String, - val gender: String, + val gender: String?, val termAgreement: List, - val birth: Int, + val birth: Int?, ) fun User.toData() = UserRequest( name = name, - gender = gender, - birth = birth, + gender = gender.ifEmpty { null }, + birth = if (birth < 0) null else birth, termAgreement = termAgreement, ) From d05e06d8987bed27d831dd4e499a7928e4a317ac Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 12:10:32 +0900 Subject: [PATCH 19/31] =?UTF-8?q?fix:=20=EC=9D=B4=EB=A6=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EC=8B=9C=20=EB=B2=84=ED=8A=BC=EC=97=90=20ImePaddin?= =?UTF-8?q?g=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/feature/loginsignup/signup/SignUpScreen.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 51b275ee..26456db1 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text @@ -215,7 +216,7 @@ fun SignUpScreen( } content() SusuFilledButton( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth().imePadding(), shape = RectangleShape, color = FilledButtonColor.Black, style = MediumButtonStyle.height60, From 47d6c2bd9af24b40ba9772ab406a1f7ce8f021f0 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 12:25:25 +0900 Subject: [PATCH 20/31] =?UTF-8?q?refactor:=20loginSignupNavGraph=20navCont?= =?UTF-8?q?roller=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../navigation/LoginSignupNavigation.kt | 33 +++---------------- .../com/susu/feature/navigator/MainScreen.kt | 3 +- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt index f9031611..4e536ce2 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt @@ -16,49 +16,26 @@ fun NavController.navigateLoginSignup(navOptions: NavOptions) { fun NavGraphBuilder.loginSignupNavGraph( padding: PaddingValues, - navController: NavController, + navigateToLogin: () -> Unit, + navigateToSignUp: () -> Unit, navigateToReceived: () -> Unit, ) { composable(route = LoginSignupRoute.Parent.Vote.route) { VoteRoute( - navigateToLogin = { - navController.navigate(LoginSignupRoute.Parent.Login.route) { - popUpTo( - route = LoginSignupRoute.Parent.Vote.route, - ) { - inclusive = true - } - } - }, + navigateToLogin = navigateToLogin, ) } composable(route = LoginSignupRoute.Parent.Login.route) { LoginRoute( navigateToReceived = navigateToReceived, - navigateToSignUp = { - navController.navigate(LoginSignupRoute.Parent.SignUp.route) { - popUpTo( - route = LoginSignupRoute.Parent.SignUp.route, - ) { - inclusive = true - } - } - }, + navigateToSignUp = navigateToSignUp, ) } composable(route = LoginSignupRoute.Parent.SignUp.route) { SignUpRoute( padding = padding, navigateToReceived = navigateToReceived, - navigateToLogin = { - navController.navigate(LoginSignupRoute.Parent.Login.route) { - popUpTo( - route = LoginSignupRoute.Parent.SignUp.route, - ) { - inclusive = true - } - } - }, + navigateToLogin = navigateToLogin, ) } } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index bbb3e5d5..9fe72050 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -53,8 +53,9 @@ internal fun MainScreen( startDestination = navigator.startDestination, ) { loginSignupNavGraph( - navController = navigator.navController, navigateToReceived = navigator::navigateSent, + navigateToLogin = navigator::navigateLogin, + navigateToSignUp = navigator::navigateSignup, padding = innerPadding ) From 4c3da1c999421e9520ac2ed0477a245a616d356c Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 12:35:42 +0900 Subject: [PATCH 21/31] refactor: sideEffect collect -> collectWithLifecycle --- .../feature/loginsignup/signup/SignUpScreen.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 26456db1..31c72076 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text 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 @@ -40,6 +39,7 @@ import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.screen.LoadingScreen import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.loginsignup.signup.content.AdditionalContent import com.susu.feature.loginsignup.signup.content.NameContent import com.susu.feature.loginsignup.signup.content.TermsContent @@ -63,13 +63,11 @@ fun SignUpRoute( viewModel.goPreviousStep() } - LaunchedEffect(key1 = viewModel.sideEffect) { - viewModel.sideEffect.collect { sideEffect -> - when (sideEffect) { - SignUpEffect.NavigateToLogin -> navigateToLogin() - SignUpEffect.NavigateToReceived -> navigateToReceived() - is SignUpEffect.ShowToast -> Toast.makeText(context, sideEffect.msg, Toast.LENGTH_SHORT).show() - } + viewModel.sideEffect.collectWithLifecycle { sideEffect -> + when (sideEffect) { + SignUpEffect.NavigateToLogin -> navigateToLogin() + SignUpEffect.NavigateToReceived -> navigateToReceived() + is SignUpEffect.ShowToast -> Toast.makeText(context, sideEffect.msg, Toast.LENGTH_SHORT).show() } } From b0884027b5a8ba8345fe36c6a2425b62ebb44620 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 12:36:34 +0900 Subject: [PATCH 22/31] =?UTF-8?q?fix:=20Login=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=A0=20=EB=95=8C=20?= =?UTF-8?q?=EB=B0=B1=EC=8A=A4=ED=83=9D=20=EB=AA=A8=EB=91=90=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그아웃, 탈퇴, 회원가입 취소 --- .../main/java/com/susu/feature/navigator/MainNavigator.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt index 6d30b094..35daed42 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainNavigator.kt @@ -69,7 +69,11 @@ internal class MainNavigator( } fun navigateLogin() { - navController.navigate(LoginSignupRoute.Parent.Login.route) + navController.navigate(LoginSignupRoute.Parent.Login.route) { + popUpTo(id = navController.graph.id) { + inclusive = true + } + } } fun navigateSignup() { From 2fac573bb5320591e02439a8a6002b085e478aad Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 12:41:45 +0900 Subject: [PATCH 23/31] refactor: Toast -> SusuSnackBar --- .../loginsignup/navigation/LoginSignupNavigation.kt | 3 +++ .../com/susu/feature/loginsignup/signup/SignUpScreen.kt | 7 +++---- .../src/main/java/com/susu/feature/navigator/MainScreen.kt | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt index 4e536ce2..cfceb4d3 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt @@ -5,6 +5,7 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable +import com.susu.core.ui.SnackbarToken import com.susu.feature.loginsignup.VoteRoute import com.susu.feature.loginsignup.login.LoginRoute import com.susu.feature.loginsignup.signup.SignUpRoute @@ -19,6 +20,7 @@ fun NavGraphBuilder.loginSignupNavGraph( navigateToLogin: () -> Unit, navigateToSignUp: () -> Unit, navigateToReceived: () -> Unit, + onShowToast: (SnackbarToken) -> Unit, ) { composable(route = LoginSignupRoute.Parent.Vote.route) { VoteRoute( @@ -36,6 +38,7 @@ fun NavGraphBuilder.loginSignupNavGraph( padding = padding, navigateToReceived = navigateToReceived, navigateToLogin = navigateToLogin, + onShowToast = onShowToast, ) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 31c72076..733bfe38 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -1,6 +1,5 @@ package com.susu.feature.loginsignup.signup -import android.widget.Toast import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope @@ -24,7 +23,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -39,6 +37,7 @@ import com.susu.core.designsystem.component.button.MediumButtonStyle import com.susu.core.designsystem.component.button.SusuFilledButton import com.susu.core.designsystem.component.screen.LoadingScreen import com.susu.core.designsystem.theme.SusuTheme +import com.susu.core.ui.SnackbarToken import com.susu.core.ui.extension.collectWithLifecycle import com.susu.feature.loginsignup.signup.content.AdditionalContent import com.susu.feature.loginsignup.signup.content.NameContent @@ -52,8 +51,8 @@ fun SignUpRoute( termViewModel: TermViewModel = hiltViewModel(), navigateToReceived: () -> Unit, navigateToLogin: () -> Unit, + onShowToast: (SnackbarToken) -> Unit = {}, ) { - val context = LocalContext.current val uiState: SignUpState by viewModel.uiState.collectAsStateWithLifecycle() val termState: TermState by termViewModel.uiState.collectAsStateWithLifecycle() @@ -67,7 +66,7 @@ fun SignUpRoute( when (sideEffect) { SignUpEffect.NavigateToLogin -> navigateToLogin() SignUpEffect.NavigateToReceived -> navigateToReceived() - is SignUpEffect.ShowToast -> Toast.makeText(context, sideEffect.msg, Toast.LENGTH_SHORT).show() + is SignUpEffect.ShowToast -> onShowToast(SnackbarToken(message = sideEffect.msg)) } } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index 9fe72050..029f0f59 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -56,7 +56,8 @@ internal fun MainScreen( navigateToReceived = navigator::navigateSent, navigateToLogin = navigator::navigateLogin, navigateToSignUp = navigator::navigateSignup, - padding = innerPadding + onShowToast = viewModel::onShowToast, + padding = innerPadding, ) sentNavGraph( From b7f1737c3a1b44e2daa57265a8ba7a3db3946e8d Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 13:04:27 +0900 Subject: [PATCH 24/31] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20=EA=B8=80=EC=9E=90=EC=88=98=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EC=B6=9C,=20updateName=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ui/src/main/java/com/susu/core/ui/Consts.kt | 2 ++ .../com/susu/feature/loginsignup/signup/SignUpViewModel.kt | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 75699cfb..2d3a368e 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -11,3 +11,5 @@ val alignList stringResource(id = R.string.word_align_high_amount), stringResource(id = R.string.word_align_low_amount), ) + +const val inputLengthLimitation = 10 diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index 8c3edb0c..a88957bb 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -3,6 +3,7 @@ package com.susu.feature.loginsignup.signup import androidx.lifecycle.viewModelScope import com.susu.core.model.User import com.susu.core.ui.base.BaseViewModel +import com.susu.core.ui.inputLengthLimitation import com.susu.domain.usecase.loginsignup.SignUpUseCase import com.susu.feature.loginsignup.social.KakaoLoginHelper import dagger.hilt.android.lifecycle.HiltViewModel @@ -16,9 +17,9 @@ class SignUpViewModel @Inject constructor( fun updateName(name: String) { val trimmedName = name.trim() - val slicedName = if (trimmedName.length > 10) trimmedName.slice(0 until 10) else trimmedName + if (trimmedName.length > inputLengthLimitation) return - intent { copy(name = slicedName, isNameValid = nameRegex.matches(slicedName)) } + intent { copy(name = trimmedName, isNameValid = nameRegex.matches(trimmedName)) } } fun updateGender(gender: Gender) { @@ -78,7 +79,7 @@ class SignUpViewModel @Inject constructor( name = uiState.value.name, gender = uiState.value.gender.content, birth = uiState.value.birth, - termAgreement = uiState.value.agreedTerms + termAgreement = uiState.value.agreedTerms, ), ).onSuccess { postSideEffect(SignUpEffect.NavigateToReceived) From be359666efb92c9e3d4b1847db94b5193df64fcc Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 13:05:15 +0900 Subject: [PATCH 25/31] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EC=A0=95=EA=B7=9C=EC=8B=9D=20=EC=83=81=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ui/src/main/java/com/susu/core/ui/Consts.kt | 1 + .../com/susu/feature/loginsignup/signup/SignUpViewModel.kt | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 2d3a368e..29a4c0aa 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -13,3 +13,4 @@ val alignList ) const val inputLengthLimitation = 10 +val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index a88957bb..a8c9d2fa 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.viewModelScope import com.susu.core.model.User import com.susu.core.ui.base.BaseViewModel import com.susu.core.ui.inputLengthLimitation +import com.susu.core.ui.nameRegex import com.susu.domain.usecase.loginsignup.SignUpUseCase import com.susu.feature.loginsignup.social.KakaoLoginHelper import dagger.hilt.android.lifecycle.HiltViewModel @@ -93,8 +94,4 @@ class SignUpViewModel @Inject constructor( } } } - - companion object { - private val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") - } } From 724f78a1ce4afa4fdf245b7e8ebf2ec348b7fe84 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 13:06:25 +0900 Subject: [PATCH 26/31] =?UTF-8?q?chore:=20TermViewModel=20isLoading=20=3D?= =?UTF-8?q?=20false=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/susu/feature/loginsignup/signup/TermViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt index e3867d08..01d3933e 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/TermViewModel.kt @@ -21,8 +21,8 @@ class TermViewModel @Inject constructor( intent { copy(terms = it, isLoading = false) } }.onFailure { postSideEffect(TermEffect.ShowToast(it.message ?: "약관을 불러오지 못했어요")) - intent { copy(isLoading = false) } } + intent { copy(isLoading = false) } } } @@ -33,8 +33,8 @@ class TermViewModel @Inject constructor( intent { copy(currentTerm = it, isLoading = false) } }.onFailure { postSideEffect(TermEffect.ShowToast(it.message ?: "약관 내용을 불러오지 못했어요")) - intent { copy(isLoading = false) } } + intent { copy(isLoading = false) } } } } From 52a9a3bf3d5e98260b2423ae3f34195e5931840a Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 13:07:20 +0900 Subject: [PATCH 27/31] chore: ktlink check --- core/model/src/main/java/com/susu/core/model/TermDetail.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/model/src/main/java/com/susu/core/model/TermDetail.kt b/core/model/src/main/java/com/susu/core/model/TermDetail.kt index 2a46e3e8..d2b9676e 100644 --- a/core/model/src/main/java/com/susu/core/model/TermDetail.kt +++ b/core/model/src/main/java/com/susu/core/model/TermDetail.kt @@ -4,5 +4,5 @@ data class TermDetail( val id: Int, val title: String, val isEssential: Boolean, - val description: String + val description: String, ) From 70347d64436e7f66d9f043b0e0c0de571f3dbf6b Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 13:22:22 +0900 Subject: [PATCH 28/31] chore: detekt check --- .../com/susu/feature/loginsignup/signup/SignUpScreen.kt | 6 ++++-- .../susu/feature/loginsignup/signup/content/NameContent.kt | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt index 733bfe38..c96e8c15 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpScreen.kt @@ -92,9 +92,11 @@ fun SignUpRoute( targetState = uiState.currentStep, label = "SignUpContent", transitionSpec = { - val direction = if (targetState.ordinal > initialState.ordinal) + val direction = if (targetState.ordinal > initialState.ordinal) { AnimatedContentTransitionScope.SlideDirection.Left - else AnimatedContentTransitionScope.SlideDirection.Right + } else { + AnimatedContentTransitionScope.SlideDirection.Right + } slideIntoContainer( towards = direction, animationSpec = tween(500), diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt index 2241db1e..3ca94d63 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/NameContent.kt @@ -13,7 +13,6 @@ import androidx.compose.ui.tooling.preview.Preview import com.susu.core.designsystem.component.textfield.SusuUnderlineTextField import com.susu.core.designsystem.theme.SusuTheme import com.susu.feature.loginsignup.R -import com.susu.feature.loginsignup.signup.SignUpStep @Composable fun NameContent( From fc0c16cae64905b75b6ae811b9d6782744204423 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 12 Jan 2024 14:22:43 +0900 Subject: [PATCH 29/31] =?UTF-8?q?rename:=20=EC=83=81=EC=88=98=20inputLengt?= =?UTF-8?q?hLimitation=20->=20USER=5FNAME=5FMAX=5FLENGTH=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/designsystem/component/appbar/SusuProgressAppBar.kt | 1 + core/ui/src/main/java/com/susu/core/ui/Consts.kt | 2 +- .../com/susu/feature/loginsignup/signup/SignUpViewModel.kt | 4 ++-- .../susu/feature/loginsignup/signup/content/TermsContent.kt | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt index 2ba54e7b..677f0734 100644 --- a/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt +++ b/core/designsystem/src/main/java/com/susu/core/designsystem/component/appbar/SusuProgressAppBar.kt @@ -43,6 +43,7 @@ fun SusuProgressAppBar( }, ) } + @Preview(showBackground = true, backgroundColor = 0xFFFFFFFF) @Composable fun SusuProgressAppBarPreview() { diff --git a/core/ui/src/main/java/com/susu/core/ui/Consts.kt b/core/ui/src/main/java/com/susu/core/ui/Consts.kt index 29a4c0aa..a8b83539 100644 --- a/core/ui/src/main/java/com/susu/core/ui/Consts.kt +++ b/core/ui/src/main/java/com/susu/core/ui/Consts.kt @@ -12,5 +12,5 @@ val alignList stringResource(id = R.string.word_align_low_amount), ) -const val inputLengthLimitation = 10 +const val USER_NAME_MAX_LENGTH = 10 val nameRegex = Regex("[a-zA-Z가-힣]{0,10}") diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index a8c9d2fa..d30b1483 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -3,7 +3,7 @@ package com.susu.feature.loginsignup.signup import androidx.lifecycle.viewModelScope import com.susu.core.model.User import com.susu.core.ui.base.BaseViewModel -import com.susu.core.ui.inputLengthLimitation +import com.susu.core.ui.USER_NAME_MAX_LENGTH import com.susu.core.ui.nameRegex import com.susu.domain.usecase.loginsignup.SignUpUseCase import com.susu.feature.loginsignup.social.KakaoLoginHelper @@ -18,7 +18,7 @@ class SignUpViewModel @Inject constructor( fun updateName(name: String) { val trimmedName = name.trim() - if (trimmedName.length > inputLengthLimitation) return + if (trimmedName.length > USER_NAME_MAX_LENGTH) return intent { copy(name = trimmedName, isNameValid = nameRegex.matches(trimmedName)) } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt index 5d993083..87050445 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/content/TermsContent.kt @@ -33,8 +33,8 @@ import com.susu.core.designsystem.theme.Gray30 import com.susu.core.designsystem.theme.Gray40 import com.susu.core.designsystem.theme.SusuTheme import com.susu.core.model.Term -import com.susu.core.ui.extension.susuClickable import com.susu.core.ui.R +import com.susu.core.ui.extension.susuClickable @Composable fun TermsContent( From 1f924287233ce16a82e52cc873a8bd47c4103131 Mon Sep 17 00:00:00 2001 From: jinukeu Date: Fri, 12 Jan 2024 14:25:49 +0900 Subject: [PATCH 30/31] chore: ktlint format --- .../java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt index d30b1483..321f91cf 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpViewModel.kt @@ -2,8 +2,8 @@ package com.susu.feature.loginsignup.signup import androidx.lifecycle.viewModelScope import com.susu.core.model.User -import com.susu.core.ui.base.BaseViewModel import com.susu.core.ui.USER_NAME_MAX_LENGTH +import com.susu.core.ui.base.BaseViewModel import com.susu.core.ui.nameRegex import com.susu.domain.usecase.loginsignup.SignUpUseCase import com.susu.feature.loginsignup.social.KakaoLoginHelper From 123019f847a7531d056905a82f6ebbbfa2ace987 Mon Sep 17 00:00:00 2001 From: yangsooplus Date: Fri, 12 Jan 2024 15:46:02 +0900 Subject: [PATCH 31/31] =?UTF-8?q?chore:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EB=A7=88=EC=A7=80=EB=A7=89=20=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20'=EB=8B=A4=EC=9D=8C'=20->=20'=EC=99=84?= =?UTF-8?q?=EB=A3=8C'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/ui/src/main/res/values/strings.xml | 1 + .../java/com/susu/feature/loginsignup/signup/SignUpContract.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 6d8b786d..e0ccb7b6 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -22,4 +22,5 @@ 여성 출생년도 다음 + 완료 diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt index de2c83bd..60d2940c 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/signup/SignUpContract.kt @@ -44,7 +44,7 @@ enum class SignUpStep( ADDITIONAL( appBarTitle = null, description = R.string.signup_additional_description, - bottomButtonText = com.susu.core.ui.R.string.word_next, + bottomButtonText = com.susu.core.ui.R.string.word_done, ), }