-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Featute/Sign Up UI #58
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package com.rootstrap.androidcomposebase.ui.pages.sign_up | ||
|
||
import androidx.compose.foundation.background | ||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.res.painterResource | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
import com.rootstrap.androidcomposebase.ui.common.AppButton | ||
import com.rootstrap.androidcomposebase.ui.common.AppTextField | ||
import com.rootstrap.androidcomposebase.ui.theme.Padding | ||
import com.rootstrap.example.app.R | ||
|
||
@Preview | ||
@Composable | ||
fun SignUpScreen( | ||
viewModel: SignUpViewModel = SignUpViewModel(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't we have any DI framework into the base yet? if so, might be better to use it. What do you think? |
||
) { | ||
val uiState by viewModel.uiState.collectAsStateWithLifecycle() | ||
Column( | ||
verticalArrangement = Arrangement.SpaceEvenly, | ||
horizontalAlignment = Alignment.CenterHorizontally, | ||
modifier = Modifier | ||
.background(Color.Black) | ||
.padding(horizontal = Padding.huge) | ||
) { | ||
Icon( | ||
painter = painterResource(id = R.drawable.rootstrap_logo), | ||
contentDescription = null, | ||
tint = Color.White | ||
) | ||
Column( | ||
verticalArrangement = Arrangement.Center | ||
) { | ||
AppTextField( | ||
value = uiState.name, | ||
onValueChange = { viewModel.onNameChanged(it) }, | ||
label = stringResource(id = R.string.sign_up_name_label), | ||
showError = uiState.showNameError, | ||
errorMessage = stringResource(id = R.string.sign_up_name_error) | ||
) | ||
|
||
AppTextField( | ||
value = uiState.email, | ||
onValueChange = { viewModel.onEmailChanged(it) }, | ||
label = stringResource(id = R.string.log_in_email_label), | ||
showError = uiState.showEmailError, | ||
errorMessage = stringResource(id = R.string.log_in_email_error) | ||
) | ||
|
||
AppTextField( | ||
value = uiState.password, | ||
onValueChange = { viewModel.onPasswordChanged(it) }, | ||
label = stringResource(id = R.string.log_in_password_label), | ||
showError = uiState.showPasswordError, | ||
errorMessage = stringResource(id = R.string.log_in_password_error), | ||
isPasswordField = true | ||
) | ||
|
||
AppTextField( | ||
value = uiState.confirmPassword, | ||
onValueChange = { viewModel.onConfirmPasswordChanged(it) }, | ||
label = stringResource(id = R.string.sign_up_confirm_password_label), | ||
showError = uiState.showConfirmPasswordError, | ||
errorMessage = stringResource(id = R.string.sign_up_confirm_password_error), | ||
isPasswordField = true | ||
) | ||
} | ||
|
||
AppButton( | ||
label = R.string.sign_up_button, enabled = uiState.isButtonEnabled | ||
) { | ||
viewModel.onSignUpButtonClicked() | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.rootstrap.androidcomposebase.ui.pages.sign_up | ||
|
||
data class SignUpUiState( | ||
val name: String = "", | ||
val showNameError: Boolean = false, | ||
val email: String = "", | ||
val showEmailError: Boolean = false, | ||
val password: String = "", | ||
val showPasswordError: Boolean = false, | ||
val confirmPassword: String = "", | ||
val showConfirmPasswordError: Boolean = false, | ||
Comment on lines
+4
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rename: |
||
) { | ||
|
||
val isButtonEnabled: Boolean | ||
get() { | ||
return name.isNotEmpty() && !showNameError && email.isNotEmpty() && !showEmailError | ||
&& password.isNotEmpty() && !showPasswordError && | ||
confirmPassword.isNotEmpty() && !showConfirmPasswordError | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please don't forget to add a new line here |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.rootstrap.androidcomposebase.ui.pages.sign_up | ||
|
||
import android.util.Patterns | ||
import androidx.lifecycle.ViewModel | ||
import com.rootstrap.androidcomposebase.ui.pages.login.LoginUiState | ||
import com.rootstrap.example.data.PatternsUtil | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.StateFlow | ||
import kotlinx.coroutines.flow.update | ||
import java.util.regex.Pattern | ||
|
||
class SignUpViewModel : ViewModel() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. before merging wait for the previous PR |
||
|
||
private var _uiState: MutableStateFlow<SignUpUiState> = MutableStateFlow(SignUpUiState()) | ||
val uiState: StateFlow<SignUpUiState> | ||
get() = _uiState | ||
|
||
fun onNameChanged(name: String) { | ||
val isNameValid = | ||
Pattern.compile(PatternsUtil.NAME_REGEX).matcher(name).matches() || name.isEmpty() | ||
_uiState.update { it.copy(name = name, showNameError = !isNameValid) } | ||
} | ||
|
||
fun onEmailChanged(email: String) { | ||
val isEmailValid = Patterns.EMAIL_ADDRESS.toRegex().matches(email) || email.isEmpty() | ||
_uiState.update { it.copy(email = email, showEmailError = !isEmailValid) } | ||
} | ||
|
||
fun onPasswordChanged(password: String) { | ||
val isPasswordValid = Pattern.compile(PatternsUtil.PASSWORD_REGEX).matcher(password) | ||
.matches() || password.isEmpty() | ||
_uiState.update { it.copy(password = password, showPasswordError = !isPasswordValid) } | ||
} | ||
|
||
fun onConfirmPasswordChanged(confirmPassword: String) { | ||
val isConfirmPasswordValid = _uiState.value.password == confirmPassword | ||
_uiState.update { | ||
it.copy( | ||
confirmPassword = confirmPassword, | ||
showConfirmPasswordError = !isConfirmPasswordValid | ||
) | ||
} | ||
} | ||
|
||
fun onSignUpButtonClicked() { | ||
// TODO: Do Sign Up request | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,11 @@ | |
<string name="log_in_password_error">Password must contain a lower case, upper case, a number and a special character</string> | ||
<string name="log_in_button">LOG IN</string> | ||
|
||
<!-- Sign Up --> | ||
<string name="sign_up_name_label">Name</string> | ||
<string name="sign_up_name_error">Name not valid</string> | ||
<string name="sign_up_confirm_password_label">Confirm Password</string> | ||
<string name="sign_up_confirm_password_error">Passwords don\'t match</string> | ||
<string name="sign_up_button">SIGN UP</string> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please capitalize only first letter |
||
|
||
</resources> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this if not needed.