Skip to content
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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.rootstrap.androidcomposebase.ui.pages.login.LogInScreen
import com.rootstrap.androidcomposebase.ui.pages.login.LogInViewModel
import com.rootstrap.androidcomposebase.ui.pages.sign_up.SignUpScreen
import com.rootstrap.androidcomposebase.ui.pages.sign_up.SignUpViewModel
Comment on lines +20 to +21
Copy link
Collaborator

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.

import com.rootstrap.androidcomposebase.ui.theme.AppTheme
import org.koin.androidx.viewmodel.ext.android.viewModel

Expand Down
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(),
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename:
name -> nameInput
email -> emailInput
password -> passwordInput
confirmPassword -> confirmPasswordInput

) {

val isButtonEnabled: Boolean
get() {
return name.isNotEmpty() && !showNameError && email.isNotEmpty() && !showEmailError
&& password.isNotEmpty() && !showPasswordError &&
confirmPassword.isNotEmpty() && !showConfirmPasswordError
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The 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() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before merging wait for the previous PR
#57
and reuse the state management logic,
if need more context write to @agustinkoll-rootstrap


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
}
}
7 changes: 7 additions & 0 deletions example/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please capitalize only first letter Sign up. Then use .uppercase() in the code if needed


</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package com.rootstrap.example.data
object PatternsUtil {

const val PASSWORD_REGEX = "^(?=.*[0-9])(?=.*[A-Z])(?=.*[@#\$%^&+=!]).{4,}\$"
const val NAME_REGEX = "^[a-zA-Z]{4,}(?: [a-zA-Z]+){0,2}\$"
}