From e9cd8401b5d8e8245781ebd42d19c5cb069d4fe7 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:25:17 +0200 Subject: [PATCH 01/11] #7 added loginscreen --- .../sel/studeez/screens/log_in/LoginScreen.kt | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginScreen.kt new file mode 100644 index 0000000..067011b --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginScreen.kt @@ -0,0 +1,52 @@ +package be.ugent.sel.studeez.screens.sign_in + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import be.ugent.sel.studeez.common.composable.* +import be.ugent.sel.studeez.common.ext.basicButton +import be.ugent.sel.studeez.common.ext.fieldModifier +import be.ugent.sel.studeez.common.ext.textButton +import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun LoginScreen( + openAndPopUp: (String, String) -> Unit, + modifier: Modifier = Modifier, + viewModel: LoginViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState + + SecondaryScreenToolbar(title = resources().getString(AppText.sign_in)) { + Column( + modifier = modifier + .fillMaxWidth() + .fillMaxHeight() + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + EmailField(uiState.email, viewModel::onEmailChange, Modifier.fieldModifier()) + PasswordField(uiState.password, viewModel::onPasswordChange, Modifier.fieldModifier()) + + BasicButton(AppText.sign_in, Modifier.basicButton()) { viewModel.onSignInClick(openAndPopUp) } + + BasicTextButton(AppText.not_already_user, Modifier.textButton()) { + viewModel.onNotAlreadyUser(openAndPopUp) + } + + BasicTextButton(AppText.forgot_password, Modifier.textButton()) { + viewModel.onForgotPasswordClick() + } + } + } +} \ No newline at end of file From fe66aa386a273763702eb68f2f53dd2a5637b931 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:25:52 +0200 Subject: [PATCH 02/11] #7 added state for login screen --- .../be/ugent/sel/studeez/screens/log_in/LoginUiState.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginUiState.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginUiState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginUiState.kt new file mode 100644 index 0000000..e1cc98a --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginUiState.kt @@ -0,0 +1,6 @@ +package be.ugent.sel.studeez.screens.sign_in + +data class LoginUiState( + val email: String = "", + val password: String = "" +) From 5bc0e51f8d5a4d43df6fe3b01fb2bc4fa009799a Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:32:18 +0200 Subject: [PATCH 03/11] #7 added login viewmodel --- .../studeez/screens/log_in/LoginViewModel.kt | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginViewModel.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginViewModel.kt new file mode 100644 index 0000000..075be2f --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/log_in/LoginViewModel.kt @@ -0,0 +1,69 @@ +package be.ugent.sel.studeez.screens.sign_in + +import androidx.compose.runtime.mutableStateOf +import be.ugent.sel.studeez.common.ext.isValidEmail +import be.ugent.sel.studeez.common.snackbar.SnackbarManager +import be.ugent.sel.studeez.domain.AccountDAO +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.navigation.StudeezDestinations +import be.ugent.sel.studeez.navigation.StudeezDestinations.LOGIN_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.SIGN_UP_SCREEN +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import be.ugent.sel.studeez.R.string as AppText + +@HiltViewModel +class LoginViewModel @Inject constructor( + private val accountDAO: AccountDAO, + logService: LogService +) : StudeezViewModel(logService) { + var uiState = mutableStateOf(LoginUiState()) + private set + + private val email + get() = uiState.value.email + private val password + get() = uiState.value.password + + fun onEmailChange(newValue: String) { + uiState.value = uiState.value.copy(email = newValue) + } + + fun onPasswordChange(newValue: String) { + uiState.value = uiState.value.copy(password = newValue) + } + + fun onSignInClick(openAndPopUp: (String, String) -> Unit) { + if (!email.isValidEmail()) { + SnackbarManager.showMessage(AppText.email_error) + return + } + + if (password.isBlank()) { + SnackbarManager.showMessage(AppText.empty_password_error) + return + } + + launchCatching { + accountDAO.signInWithEmailAndPassword(email, password) + openAndPopUp(SIGN_UP_SCREEN, LOGIN_SCREEN) // Is not reached when error occurs. + } + } + + fun onForgotPasswordClick() { + if (!email.isValidEmail()) { + SnackbarManager.showMessage(AppText.email_error) + return + } + + launchCatching { + accountDAO.sendRecoveryEmail(email) + SnackbarManager.showMessage(AppText.recovery_email_sent) + } + } + + fun onNotAlreadyUser(openAndPopUp: (String, String) -> Unit) { + openAndPopUp(SIGN_UP_SCREEN, LOGIN_SCREEN) + } +} \ No newline at end of file From c6e53ff45c5333d6ed39b341ef53be346fe68c77 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:33:20 +0200 Subject: [PATCH 04/11] #5 added signup screen --- .../studeez/screens/sign_up/SignUpScreen.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpScreen.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpScreen.kt b/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpScreen.kt new file mode 100644 index 0000000..4d07f59 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpScreen.kt @@ -0,0 +1,54 @@ +package be.ugent.sel.studeez.screens.sign_up + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import be.ugent.sel.studeez.common.composable.* +import be.ugent.sel.studeez.common.ext.basicButton +import be.ugent.sel.studeez.common.ext.fieldModifier +import be.ugent.sel.studeez.common.ext.textButton +import be.ugent.sel.studeez.resources +import be.ugent.sel.studeez.R.string as AppText + +@Composable +fun SignUpScreen( + openAndPopUp: (String, String) -> Unit, + modifier: Modifier = Modifier, + viewModel: SignUpViewModel = hiltViewModel() +) { + val uiState by viewModel.uiState + val fieldModifier = Modifier.fieldModifier() + + SecondaryScreenToolbar(title = resources().getString(AppText.create_account)) { + Column( + modifier = modifier + .fillMaxWidth() + .fillMaxHeight() + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + EmailField(uiState.email, viewModel::onEmailChange, fieldModifier) + PasswordField(uiState.password, viewModel::onPasswordChange, fieldModifier) + RepeatPasswordField(uiState.repeatPassword, viewModel::onRepeatPasswordChange, fieldModifier) + + BasicButton(AppText.create_account, Modifier.basicButton()) { + viewModel.onSignUpClick(openAndPopUp) + } + + BasicTextButton(AppText.already_user, Modifier.textButton()) { + viewModel.onLoginScreenClick(openAndPopUp) + } + } + } + + +} \ No newline at end of file From 2f5e7e31aa6a9bae750a99e59bc64bf45cbe838d Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:33:47 +0200 Subject: [PATCH 05/11] #5 added sign up ui state --- .../be/ugent/sel/studeez/screens/sign_up/SignUpUiState.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpUiState.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpUiState.kt b/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpUiState.kt new file mode 100644 index 0000000..081eb42 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpUiState.kt @@ -0,0 +1,7 @@ +package be.ugent.sel.studeez.screens.sign_up + +data class SignUpUiState( + val email: String = "", + val password: String = "", + val repeatPassword: String = "" +) From d3d5bb7dbe35033641850ad61a0f346c785b7615 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:34:16 +0200 Subject: [PATCH 06/11] added sign up viewmodel --- .../screens/sign_up/SignUpViewModel.kt | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpViewModel.kt diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpViewModel.kt new file mode 100644 index 0000000..a22fe68 --- /dev/null +++ b/app/src/main/java/be/ugent/sel/studeez/screens/sign_up/SignUpViewModel.kt @@ -0,0 +1,67 @@ +package be.ugent.sel.studeez.screens.sign_up + +import androidx.compose.runtime.mutableStateOf +import be.ugent.sel.studeez.common.ext.isValidEmail +import be.ugent.sel.studeez.common.ext.isValidPassword +import be.ugent.sel.studeez.common.ext.passwordMatches +import be.ugent.sel.studeez.common.snackbar.SnackbarManager +import be.ugent.sel.studeez.domain.AccountDAO +import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.navigation.StudeezDestinations.LOGIN_SCREEN +import be.ugent.sel.studeez.navigation.StudeezDestinations.SIGN_UP_SCREEN +import be.ugent.sel.studeez.screens.StudeezViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import be.ugent.sel.studeez.R.string as AppText +import javax.inject.Inject + +@HiltViewModel +class SignUpViewModel @Inject constructor( + private val accountService: AccountDAO, + logService: LogService + ) : StudeezViewModel(logService) { + var uiState = mutableStateOf(SignUpUiState()) + private set + + private val email + get() = uiState.value.email + private val password + get() = uiState.value.password + + fun onEmailChange(newValue: String) { + uiState.value = uiState.value.copy(email = newValue) + } + + fun onPasswordChange(newValue: String) { + uiState.value = uiState.value.copy(password = newValue) + } + + fun onRepeatPasswordChange(newValue: String) { + uiState.value = uiState.value.copy(repeatPassword = newValue) + } + + fun onSignUpClick(openAndPopUp: (String, String) -> Unit) { + if (!email.isValidEmail()) { + SnackbarManager.showMessage(AppText.email_error) + return + } + + if (!password.isValidPassword()) { + SnackbarManager.showMessage(AppText.password_error) + return + } + + if (!password.passwordMatches(uiState.value.repeatPassword)) { + SnackbarManager.showMessage(AppText.password_match_error) + return + } + + launchCatching { + accountService.signUpWithEmailAndPassword(email, password) + openAndPopUp(LOGIN_SCREEN, SIGN_UP_SCREEN) + } + } + + fun onLoginScreenClick(openAndPopUp: (String, String) -> Unit) { + openAndPopUp(LOGIN_SCREEN, SIGN_UP_SCREEN) + } +} \ No newline at end of file From b2382931cbc37da3c91e42fa7cb57d80fbebd8a7 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:34:53 +0200 Subject: [PATCH 07/11] #7 added login route to navgraph --- app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index 2706a9a..272630e 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -18,6 +18,8 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import be.ugent.sel.studeez.common.snackbar.SnackbarManager import be.ugent.sel.studeez.navigation.StudeezDestinations +import be.ugent.sel.studeez.screens.sign_in.LoginScreen +import be.ugent.sel.studeez.screens.sign_up.SignUpScreen import be.ugent.sel.studeez.screens.splash.SplashScreen import be.ugent.sel.studeez.ui.theme.StudeezTheme import kotlinx.coroutines.CoroutineScope @@ -77,5 +79,7 @@ fun NavGraphBuilder.studeezGraph(appState: StudeezAppstate) { SplashScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) }) } - + composable(StudeezDestinations.LOGIN_SCREEN) { + LoginScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) }) + } } \ No newline at end of file From 97569f9a9f8f9c48b833cbb9f6e8e264a2fbe72d Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:35:44 +0200 Subject: [PATCH 08/11] #5 added signup route to navgraph --- app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt index 272630e..0467234 100644 --- a/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt +++ b/app/src/main/java/be/ugent/sel/studeez/StudeezApp.kt @@ -82,4 +82,8 @@ fun NavGraphBuilder.studeezGraph(appState: StudeezAppstate) { composable(StudeezDestinations.LOGIN_SCREEN) { LoginScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) }) } + + composable(StudeezDestinations.SIGN_UP_SCREEN) { + SignUpScreen(openAndPopUp = { route, popUp -> appState.navigateAndPopUp(route, popUp) }) + } } \ No newline at end of file From aa633421951e0f3011d4af612249ffab5c020d29 Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:38:00 +0200 Subject: [PATCH 09/11] splash screen now reroutes to sign up screen --- .../be/ugent/sel/studeez/screens/splash/SplashViewModel.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt index f019c8c..e617fff 100644 --- a/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt +++ b/app/src/main/java/be/ugent/sel/studeez/screens/splash/SplashViewModel.kt @@ -3,6 +3,7 @@ package be.ugent.sel.studeez.screens.splash import androidx.compose.runtime.mutableStateOf import be.ugent.sel.studeez.domain.AccountDAO import be.ugent.sel.studeez.domain.LogService +import be.ugent.sel.studeez.navigation.StudeezDestinations import be.ugent.sel.studeez.screens.StudeezViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -18,9 +19,10 @@ class SplashViewModel @Inject constructor( showError.value = false if (accountDAO.hasUser) { - // openAndPopUp( , SPLASH_SCREEN) + // TODO this should go to the home page + openAndPopUp(StudeezDestinations.SIGN_UP_SCREEN, StudeezDestinations.SPLASH_SCREEN) } else{ - // openAndPopUp(, SPLASH_SCREEN) + openAndPopUp(StudeezDestinations.SIGN_UP_SCREEN, StudeezDestinations.SPLASH_SCREEN) } } } \ No newline at end of file From 36fb4620c3a73f8c49200a860c7fadbfb379597f Mon Sep 17 00:00:00 2001 From: lbarraga Date: Sat, 8 Apr 2023 22:39:54 +0200 Subject: [PATCH 10/11] SecondaryScreenToolbar now accepts composables as content --- .../be/ugent/sel/studeez/common/composable/ToolbarComposable.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/ugent/sel/studeez/common/composable/ToolbarComposable.kt b/app/src/main/java/be/ugent/sel/studeez/common/composable/ToolbarComposable.kt index 2e3d635..9002bf9 100644 --- a/app/src/main/java/be/ugent/sel/studeez/common/composable/ToolbarComposable.kt +++ b/app/src/main/java/be/ugent/sel/studeez/common/composable/ToolbarComposable.kt @@ -41,7 +41,7 @@ fun PrimaryScreenToolbar( // Does not contain floatingActionButton and bottom bar, used in all the other screens fun SecondaryScreenToolbar( title: String, - content: (PaddingValues) -> Unit + content: @Composable (PaddingValues) -> Unit ) { Scaffold( // Everything at the top of the screen From 815c166fc877014051c123a3ff3c9cb2b9cedcb0 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Sun, 9 Apr 2023 08:07:40 +0200 Subject: [PATCH 11/11] Fix typo in strings.xml Add point because consistencu --- app/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 79d0a41..6daa9bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,8 +19,8 @@ Don\'t have an account yet? Sign up. Sign in Enter your login details - Forgot password? Click to get recovery email + Forgot password? Click to get recovery email. Check your inbox for the recovery email. Password cannot be empty. - \ No newline at end of file +