From 7d1f1ef6fcc0216c7962d651dfa53ffb01f7e803 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Thu, 8 Sep 2022 13:49:34 -0700 Subject: [PATCH] add create user profile view --- .../java/app/omnivore/omnivore/Constants.kt | 1 + .../omnivore/omnivore/DatastoreRepository.kt | 6 + .../omnivore/ui/auth/CreateUserProfile.kt | 127 ++++++++++++++++++ .../omnivore/ui/auth/LoginViewModel.kt | 20 ++- .../omnivore/ui/auth/WelcomeScreen.kt | 3 + 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/CreateUserProfile.kt diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/Constants.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/Constants.kt index b351e3ecf..3b219d6a3 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/Constants.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/Constants.kt @@ -9,6 +9,7 @@ object Constants { object DatastoreKeys { const val omnivoreAuthToken = "omnivoreAuthToken" const val omnivoreAuthCookieString = "omnivoreAuthCookieString" + const val omnivorePendingUserToken = "omnivorePendingUserToken" } object AppleConstants { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DatastoreRepository.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DatastoreRepository.kt index 7392ffeb9..725054822 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DatastoreRepository.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/DatastoreRepository.kt @@ -16,6 +16,7 @@ interface DatastoreRepository { suspend fun putInt(key: String, value: Int) suspend fun getString(key: String): String? suspend fun getInt(key: String): Int? + suspend fun clearValue(key: String) } class OmnivoreDatastore @Inject constructor( @@ -55,6 +56,11 @@ class OmnivoreDatastore @Inject constructor( context.dataStore.edit { it.clear() } } + override suspend fun clearValue(key: String) { + val preferencesKey = stringPreferencesKey(key) + context.dataStore.edit { it.remove(preferencesKey) } + } + override val hasAuthTokenFlow: Flow = context .dataStore.data.map { preferences -> val key = stringPreferencesKey(DatastoreKeys.omnivoreAuthToken) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/CreateUserProfile.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/CreateUserProfile.kt new file mode 100644 index 000000000..c8229c9a2 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/CreateUserProfile.kt @@ -0,0 +1,127 @@ +package app.omnivore.omnivore.ui.auth + +import android.annotation.SuppressLint +import android.widget.Toast +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.text.ClickableText +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import app.omnivore.omnivore.R + +@SuppressLint("CoroutineCreationDuringComposition") +@Composable +fun CreateUserProfileView(viewModel: LoginViewModel) { + var name by rememberSaveable { mutableStateOf("") } + var username by rememberSaveable { mutableStateOf("") } + + Row( + horizontalArrangement = Arrangement.Center + ) { + Spacer(modifier = Modifier.weight(1.0F)) + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Create Your Profile", + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(bottom = 8.dp) + ) + UserProfileFields( + name = name, + username = username, + onNameChange = { name = it }, + onUsernameChange = { username = it }, + onSubmit = { } // TODO: add viewModel function + ) + + // TODO: add a activity indicator (maybe after a delay?) + if (viewModel.isLoading) { + Text("Loading...") + } + + ClickableText( + text = AnnotatedString("Cancel Sign Up"), + style = MaterialTheme.typography.titleMedium + .plus(TextStyle(textDecoration = TextDecoration.Underline)), + onClick = { viewModel.cancelNewUserSignUp() } + ) + } + Spacer(modifier = Modifier.weight(1.0F)) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun UserProfileFields( + name: String, + username: String, + onNameChange: (String) -> Unit, + onUsernameChange: (String) -> Unit, + onSubmit: () -> Unit +) { + val context = LocalContext.current + val focusManager = LocalFocusManager.current + + Column( + modifier = Modifier + .fillMaxWidth() + .height(300.dp), + 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") }, + label = { Text(text = "Name") }, + onValueChange = onNameChange, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + 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() + } + }, colors = ButtonDefaults.buttonColors( + contentColor = Color(0xFF3D3D3D), + containerColor = Color(0xffffd234) + ) + ) { + Text( + text = "Submit", + modifier = Modifier.padding(horizontal = 100.dp) + ) + } + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/LoginViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/LoginViewModel.kt index ea58de14a..62391b05d 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/LoginViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/LoginViewModel.kt @@ -17,7 +17,8 @@ import javax.inject.Inject enum class RegistrationState { SocialLogin, - EmailSignIn + EmailSignIn, + PendingUser } @HiltViewModel @@ -35,7 +36,7 @@ class LoginViewModel @Inject constructor( .distinctUntilChanged() .asLiveData() - val registrationStateLiveData = MutableLiveData(RegistrationState.SocialLogin) + val registrationStateLiveData = MutableLiveData(RegistrationState.PendingUser) // TODO: set back to social login fun getAuthCookieString(): String? = runBlocking { datastoreRepo.getString(DatastoreKeys.omnivoreAuthCookieString) @@ -49,6 +50,13 @@ class LoginViewModel @Inject constructor( registrationStateLiveData.value = RegistrationState.EmailSignIn } + fun cancelNewUserSignUp() { + viewModelScope.launch { + datastoreRepo.clearValue(DatastoreKeys.omnivorePendingUserToken) + } + showSocialLogin() + } + fun login(email: String, password: String) { val emailLogin = RetrofitHelper.getInstance().create(EmailLoginSubmit::class.java) @@ -163,9 +171,15 @@ class LoginViewModel @Inject constructor( isLoading = false if (result.body()?.pendingUserToken != null) { - // store in datastore + datastoreRepo.putString( + DatastoreKeys.omnivorePendingUserToken, result.body()?.pendingUserToken!! + ) + registrationStateLiveData.value = RegistrationState.PendingUser } else { errorMessage = "Something went wrong. Please check your credentials and try again" } } } + + +// TODO: set registrationState to pending if user has pending token diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/WelcomeScreen.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/WelcomeScreen.kt index cdcab04e0..2996c81c4 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/WelcomeScreen.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/auth/WelcomeScreen.kt @@ -80,6 +80,9 @@ fun WelcomeScreenContent(viewModel: LoginViewModel) { AuthProviderView(viewModel = viewModel) } + RegistrationState.PendingUser -> { + CreateUserProfileView(viewModel = viewModel) + } } Spacer(modifier = Modifier.weight(1.0F))