add username validation

This commit is contained in:
Satindar Dhillon 2022-09-08 21:36:33 -07:00
parent 721226c6cc
commit 20f618a1e6
2 changed files with 99 additions and 26 deletions

View file

@ -44,8 +44,13 @@ fun CreateUserProfileView(viewModel: LoginViewModel) {
UserProfileFields(
name = name,
username = username,
usernameValidationErrorMessage = viewModel.usernameValidationErrorMessage,
showUsernameAsAvailable = viewModel.hasValidUsername,
onNameChange = { name = it },
onUsernameChange = { username = it },
onUsernameChange = {
username = it
viewModel.validateUsername(it)
},
onSubmit = { } // TODO: add viewModel function
)
@ -70,6 +75,8 @@ fun CreateUserProfileView(viewModel: LoginViewModel) {
fun UserProfileFields(
name: String,
username: String,
usernameValidationErrorMessage: String?,
showUsernameAsAvailable: Boolean, // TODO: use this to add green checkmark
onNameChange: (String) -> Unit,
onUsernameChange: (String) -> Unit,
onSubmit: () -> Unit
@ -84,15 +91,6 @@ fun UserProfileFields(
verticalArrangement = Arrangement.spacedBy(25.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = username,
placeholder = { Text(text = "Username") },
label = { Text(text = "Username") },
onValueChange = onUsernameChange,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() })
)
OutlinedTextField(
value = name,
placeholder = { Text(text = "Name") },
@ -102,21 +100,44 @@ fun UserProfileFields(
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() })
)
Button(onClick = {
if (name.isNotBlank() && username.isNotBlank()) {
onSubmit()
focusManager.clearFocus()
} else {
Toast.makeText(
context,
"Please enter a valid username and password.",
Toast.LENGTH_SHORT
).show()
Column(
verticalArrangement = Arrangement.spacedBy(5.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = username,
placeholder = { Text(text = "Username") },
label = { Text(text = "Username") },
onValueChange = onUsernameChange,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() })
)
if (usernameValidationErrorMessage != null) {
Text(
text = usernameValidationErrorMessage!!,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.error,
)
}
}, colors = ButtonDefaults.buttonColors(
contentColor = Color(0xFF3D3D3D),
containerColor = Color(0xffffd234)
)
}
Button(
onClick = {
if (name.isNotBlank() && username.isNotBlank()) {
onSubmit()
focusManager.clearFocus()
} else {
Toast.makeText(
context,
"Please enter a valid username and password.",
Toast.LENGTH_SHORT
).show()
}
}, colors = ButtonDefaults.buttonColors(
contentColor = Color(0xFF3D3D3D),
containerColor = Color(0xffffd234)
)
) {
Text(
text = "Submit",

View file

@ -5,16 +5,21 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.*
import app.omnivore.omnivore.*
import app.omnivore.omnivore.graphql.generated.SearchQuery
import app.omnivore.omnivore.graphql.generated.ValidateUsernameQuery
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.Optional
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tasks.Task
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import javax.inject.Inject
enum class RegistrationState {
SocialLogin,
EmailSignIn,
@ -25,18 +30,26 @@ enum class RegistrationState {
class LoginViewModel @Inject constructor(
private val datastoreRepo: DatastoreRepository
): ViewModel() {
private var validateUsernameJob: Job? = null
var isLoading by mutableStateOf(false)
private set
var errorMessage by mutableStateOf<String?>(null)
private set
var hasValidUsername by mutableStateOf<Boolean>(false)
private set
var usernameValidationErrorMessage by mutableStateOf<String?>(null)
private set
val hasAuthTokenLiveData: LiveData<Boolean> = datastoreRepo
.hasAuthTokenFlow
.distinctUntilChanged()
.asLiveData()
val registrationStateLiveData = MutableLiveData(RegistrationState.SocialLogin)
val registrationStateLiveData = MutableLiveData(RegistrationState.PendingUser) // TODO: switch back to Social
fun getAuthCookieString(): String? = runBlocking {
datastoreRepo.getString(DatastoreKeys.omnivoreAuthCookieString)
@ -57,6 +70,45 @@ class LoginViewModel @Inject constructor(
showSocialLogin()
}
fun validateUsername(potentialUsername: String) {
validateUsernameJob?.cancel()
validateUsernameJob = viewModelScope.launch {
delay(500)
// Check the username requirements first
if (potentialUsername.isEmpty()) {
usernameValidationErrorMessage = null
hasValidUsername = false
return@launch
}
if (potentialUsername.length < 4 || potentialUsername.length > 15) {
usernameValidationErrorMessage = "Username must be between 4 and 15 characters long."
hasValidUsername = false
return@launch
}
// TODO: check email regex
val apolloClient = ApolloClient.Builder()
.serverUrl("${Constants.apiURL}/api/graphql")
.build()
val response = apolloClient.query(
ValidateUsernameQuery(username = potentialUsername)
).execute()
if (response.data?.validateUsername == true) {
usernameValidationErrorMessage = null
hasValidUsername = true
} else {
hasValidUsername = false
usernameValidationErrorMessage = "This username is not available."
}
}
}
fun login(email: String, password: String) {
val emailLogin = RetrofitHelper.getInstance().create(EmailLoginSubmit::class.java)