From 5c677bca989a8451b51f133ae90c17117c8f831f Mon Sep 17 00:00:00 2001 From: Puvikaran Santhirasegaram <74664443+Puvikaran2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:22:59 +0200 Subject: [PATCH] Refactor --- .../schedulingfrontend/loginpage/LoginPage.kt | 133 +++++------------- .../sharedcomponents/Heading.kt | 43 ++++++ .../sharedcomponents/TextFields.kt | 53 +++++++ .../signuppage/SignUpPage.kt | 133 ++++-------------- 4 files changed, 156 insertions(+), 206 deletions(-) create mode 100644 frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/Heading.kt diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/loginpage/LoginPage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/loginpage/LoginPage.kt index 836be69a..1dc4a6aa 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/loginpage/LoginPage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/loginpage/LoginPage.kt @@ -1,24 +1,15 @@ package dk.scheduling.schedulingfrontend.loginpage -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Visibility -import androidx.compose.material.icons.filled.VisibilityOff -import androidx.compose.material3.Button -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -26,13 +17,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp +import dk.scheduling.schedulingfrontend.sharedcomponents.FilledButton +import dk.scheduling.schedulingfrontend.sharedcomponents.PasswordTextField +import dk.scheduling.schedulingfrontend.sharedcomponents.StandardTextField +import dk.scheduling.schedulingfrontend.sharedcomponents.Title import dk.scheduling.schedulingfrontend.ui.theme.SchedulingFrontendTheme @Composable @@ -47,13 +37,12 @@ fun LoginPage( var password by remember { mutableStateOf("") } - var showPassword by remember { - mutableStateOf(false) - } - var loginFail by remember { + var isLoginFailed by remember { mutableStateOf(false) } + Title(titleText = "Login") + Column( modifier = modifier @@ -62,75 +51,47 @@ fun LoginPage( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Column { - TextLabel("Username") - TextField( - value = username, - onValueChange = { - username = it - if (loginFail) loginFail = false - }, - modifier = - Modifier - .fillMaxWidth() - .border( - color = if (loginFail) MaterialTheme.colorScheme.error else Color.Black, - width = 1.dp, - ), - singleLine = true, - ) - } + StandardTextField( + label = "Username", + value = username, + onValueChange = { + username = it + if (isLoginFailed) isLoginFailed = false + }, + isError = isLoginFailed, + ) + Spacer(modifier = Modifier.height(20.dp)) - Column { - TextLabel("Password") - TextField( - value = password, - onValueChange = { - password = it - if (loginFail) loginFail = false - }, - visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), - modifier = - Modifier - .fillMaxWidth() - .border( - color = if (loginFail) MaterialTheme.colorScheme.error else Color.Black, - width = 1.dp, - ), - trailingIcon = { - PasswordVisibilityToggleIcon( - showPassword = showPassword, - onTogglePasswordVisibility = { showPassword = !showPassword }, - ) - }, - ) - } - if (loginFail) { + PasswordTextField( + password, + onPasswordChange = { + password = it + if (isLoginFailed) isLoginFailed = false + }, + isError = isLoginFailed, + ) + + if (isLoginFailed) { Spacer(modifier = Modifier.height(20.dp)) Text( text = "Wrong username or password", color = MaterialTheme.colorScheme.error, - style = - TextStyle( - fontSize = 15.sp, - ), ) } Spacer(modifier = Modifier.height(30.dp)) - Column { - Button(onClick = { + FilledButton( + onClick = { if (login(username, password)) { navigateOnValidLogin() } else { - loginFail = true + isLoginFailed = true } - }, modifier = Modifier.fillMaxWidth()) { - Text("Log In") - } - } + }, + text = "Log In", + ) } Column( @@ -148,30 +109,6 @@ fun LoginPage( } } -@Composable -fun TextLabel(label: String) { - Text( - label, - style = - TextStyle( - fontSize = 15.sp, - ), - ) -} - -@Composable -fun PasswordVisibilityToggleIcon( - showPassword: Boolean, - onTogglePasswordVisibility: () -> Unit, -) { - val image = if (showPassword) Icons.Filled.Visibility else Icons.Filled.VisibilityOff - val contentDescription = if (showPassword) "Hide password" else "Show password" - - IconButton(onClick = onTogglePasswordVisibility) { - Icon(imageVector = image, contentDescription = contentDescription) - } -} - fun login( username: String, password: String, @@ -183,7 +120,7 @@ fun login( @Preview(showBackground = true, device = "spec:id=reference_phone,shape=Normal,width=411,height=891,unit=dp,dpi=420") @Composable fun LoginPagePreviewLightMode() { - SchedulingFrontendTheme(darkTheme = false) { + SchedulingFrontendTheme(darkTheme = false, dynamicColor = false) { LoginPage(navigateOnValidLogin = {}, navigateToSignUpPage = {}) } } @@ -191,7 +128,7 @@ fun LoginPagePreviewLightMode() { @Preview(showBackground = true, device = "spec:id=reference_phone,shape=Normal,width=411,height=891,unit=dp,dpi=420") @Composable fun LoginPagePreviewDarkMode() { - SchedulingFrontendTheme(darkTheme = true) { + SchedulingFrontendTheme(darkTheme = true, dynamicColor = false) { LoginPage(navigateOnValidLogin = {}, navigateToSignUpPage = {}) } } diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/Heading.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/Heading.kt new file mode 100644 index 00000000..119f66b2 --- /dev/null +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/Heading.kt @@ -0,0 +1,43 @@ +package dk.scheduling.schedulingfrontend.sharedcomponents + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.em + +@Composable +fun Title( + modifier: Modifier = Modifier, + titleText: String, + topMargin: Dp = 90.dp, +) { + Column( + modifier = + modifier + .fillMaxSize() + .padding(all = 50.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Top, + ) { + Spacer(modifier = Modifier.height(topMargin)) + Text( + text = titleText, + fontSize = 7.em, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight(700), + ) + } +} diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/TextFields.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/TextFields.kt index 62f1e6eb..417099d2 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/TextFields.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/sharedcomponents/TextFields.kt @@ -2,10 +2,21 @@ package dk.scheduling.schedulingfrontend.sharedcomponents import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation @Composable fun StandardTextField( @@ -15,6 +26,8 @@ fun StandardTextField( onValueChange: (String) -> Unit, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, isError: Boolean = false, + visualTransformation: VisualTransformation = VisualTransformation.None, + trailingIcon: @Composable (() -> Unit)? = null, ) { OutlinedTextField( label = { Text(label) }, @@ -26,5 +39,45 @@ fun StandardTextField( singleLine = true, keyboardOptions = keyboardOptions, isError = isError, + visualTransformation = visualTransformation, + trailingIcon = trailingIcon, ) } + +@Composable +fun PasswordTextField( + password: String, + onPasswordChange: (String) -> Unit, + isError: Boolean = false, +) { + var showPassword by remember { + mutableStateOf(false) + } + + StandardTextField( + label = "Password", + value = password, + onValueChange = onPasswordChange, + visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + PasswordVisibilityToggleIcon( + showPassword = showPassword, + onTogglePasswordVisibility = { showPassword = !showPassword }, + ) + }, + isError = isError, + ) +} + +@Composable +fun PasswordVisibilityToggleIcon( + showPassword: Boolean, + onTogglePasswordVisibility: () -> Unit, +) { + val image = if (showPassword) Icons.Filled.Visibility else Icons.Filled.VisibilityOff + val contentDescription = if (showPassword) "Hide password" else "Show password" + + IconButton(onClick = onTogglePasswordVisibility) { + Icon(imageVector = image, contentDescription = contentDescription) + } +} diff --git a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/signuppage/SignUpPage.kt b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/signuppage/SignUpPage.kt index 3675a06a..21e8c933 100644 --- a/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/signuppage/SignUpPage.kt +++ b/frontend/app/src/main/java/dk/scheduling/schedulingfrontend/signuppage/SignUpPage.kt @@ -1,24 +1,15 @@ package dk.scheduling.schedulingfrontend.signuppage -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Visibility -import androidx.compose.material.icons.filled.VisibilityOff -import androidx.compose.material3.Button -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -26,13 +17,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp +import dk.scheduling.schedulingfrontend.sharedcomponents.FilledButton +import dk.scheduling.schedulingfrontend.sharedcomponents.PasswordTextField +import dk.scheduling.schedulingfrontend.sharedcomponents.StandardTextField +import dk.scheduling.schedulingfrontend.sharedcomponents.Title import dk.scheduling.schedulingfrontend.ui.theme.SchedulingFrontendTheme @Composable @@ -50,10 +40,12 @@ fun SignUpPage( var homeAddress by remember { mutableStateOf("") } - var signupFail by remember { + var isSignUpFailed by remember { mutableStateOf(false) } + Title(titleText = "Sign Up") + Column( modifier = modifier @@ -63,12 +55,13 @@ fun SignUpPage( verticalArrangement = Arrangement.Center, ) { StandardTextField( - "Username", - username, + label = "Username", + value = username, onValueChange = { username = it - if (signupFail) signupFail = false + if (isSignUpFailed) isSignUpFailed = false }, + isError = isSignUpFailed, ) Spacer(modifier = Modifier.height(20.dp)) @@ -77,43 +70,43 @@ fun SignUpPage( password, onPasswordChange = { password = it - if (signupFail) signupFail = false + if (isSignUpFailed) isSignUpFailed = false }, + isError = isSignUpFailed, ) Spacer(modifier = Modifier.height(20.dp)) StandardTextField( - "Home Address", - homeAddress, + label = "Home Address", + value = homeAddress, onValueChange = { homeAddress = it - if (signupFail) signupFail = false + if (isSignUpFailed) isSignUpFailed = false }, + isError = isSignUpFailed, ) - if (signupFail) { + if (isSignUpFailed) { Spacer(modifier = Modifier.height(20.dp)) Text( text = "Wrong sign up information", color = MaterialTheme.colorScheme.error, - style = TextStyle(fontSize = 15.sp), ) } Spacer(modifier = Modifier.height(30.dp)) - Column { - Button(onClick = { + FilledButton( + onClick = { if (signUp(username, password, homeAddress)) { navigateOnValidSignUp() } else { - signupFail = true + isSignUpFailed = true } - }, modifier = Modifier.fillMaxWidth()) { - Text("Sign up") - } - } + }, + text = "Sign up", + ) } Column( @@ -131,82 +124,6 @@ fun SignUpPage( } } -@Composable -fun TextLabel(label: String) { - Text( - label, - style = TextStyle(fontSize = 15.sp), - ) -} - -@Composable -fun StandardTextField( - label: String, - value: String, - onValueChange: (String) -> Unit, -) { - Column { - TextLabel(label) - TextField( - value = value, - onValueChange = onValueChange, - modifier = - Modifier - .fillMaxWidth() - .border( - color = Color.Black, - width = 1.dp, - ), - singleLine = true, - ) - } -} - -@Composable -fun PasswordTextField( - password: String, - onPasswordChange: (String) -> Unit, -) { - var showPassword by remember { - mutableStateOf(false) - } - - Column { - TextLabel("Password") - TextField( - value = password, - onValueChange = onPasswordChange, - visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), - modifier = - Modifier - .fillMaxWidth() - .border( - color = Color.Black, - width = 1.dp, - ), - trailingIcon = { - PasswordVisibilityToggleIcon( - showPassword = showPassword, - onTogglePasswordVisibility = { showPassword = !showPassword }, - ) - }, - ) - } -} - -@Composable -fun PasswordVisibilityToggleIcon( - showPassword: Boolean, - onTogglePasswordVisibility: () -> Unit, -) { - val image = if (showPassword) Icons.Filled.Visibility else Icons.Filled.VisibilityOff - val contentDescription = if (showPassword) "Hide password" else "Show password" - - IconButton(onClick = onTogglePasswordVisibility) { - Icon(imageVector = image, contentDescription = contentDescription) - } -} - fun signUp( username: String, password: String, @@ -219,7 +136,7 @@ fun signUp( @Preview(showBackground = true, device = "spec:id=reference_phone,shape=Normal,width=411,height=891,unit=dp,dpi=420") @Composable fun SignUpPagePreviewLightMode() { - SchedulingFrontendTheme(darkTheme = false) { + SchedulingFrontendTheme(darkTheme = false, dynamicColor = false) { SignUpPage(navigateOnValidSignUp = {}, navigateToLoginPage = {}) } }