diff --git a/app/src/main/java/com/example/belindas_closet/Routes.kt b/app/src/main/java/com/example/belindas_closet/Routes.kt
index da4405ab..11dc1f9f 100644
--- a/app/src/main/java/com/example/belindas_closet/Routes.kt
+++ b/app/src/main/java/com/example/belindas_closet/Routes.kt
@@ -8,6 +8,7 @@ sealed class Routes (val route: String) {
object SignUp: Routes("SignUp")
object AddProduct: Routes("Add Product")
object ForgotPassword: Routes("Forgot Password")
+ object ResetPassword: Routes("Reset Password")
object IndividualProduct: Routes("Individual_Product")
object IndividualProductUpdatePage: Routes("Individual_Product_Update")
object AdminView: Routes("Admin_View")
diff --git a/app/src/main/java/com/example/belindas_closet/screen/ResetPassword.kt b/app/src/main/java/com/example/belindas_closet/screen/ResetPassword.kt
new file mode 100644
index 00000000..b101d8e6
--- /dev/null
+++ b/app/src/main/java/com/example/belindas_closet/screen/ResetPassword.kt
@@ -0,0 +1,256 @@
+package com.example.belindas_closet.screen
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.Menu
+import androidx.compose.material3.Button
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavHostController
+import com.example.belindas_closet.R
+import com.example.belindas_closet.Routes
+import kotlinx.coroutines.launch
+
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
+@Composable
+fun ResetPasswordPage(navController: NavHostController) {
+ var password by remember { mutableStateOf("") }
+ var confirmPassword by remember { mutableStateOf("") }
+ var isPasswordValid by remember { mutableStateOf(true) }
+ var doPasswordsMatch by remember { mutableStateOf(true) }
+ var isPasswordVisible by remember { mutableStateOf(false) }
+ var isConfirmPasswordVisible by remember { mutableStateOf(false) }
+ val coroutineScope = rememberCoroutineScope()
+ val keyboardController = LocalSoftwareKeyboardController.current
+
+ Scaffold(
+ modifier = Modifier
+ .fillMaxSize(),
+ topBar = {
+ TopAppBar(
+ title = { Text("Login") },
+ navigationIcon = {
+ IconButton(
+ onClick = {
+ navController.navigate(Routes.Login.route) {
+ popUpTo(Routes.Login.route) {
+ inclusive = true
+ }
+ }
+ }
+ ) {
+ Icon(imageVector = Icons.Default.ArrowBack, contentDescription = stringResource(
+ id = R.string.reset_new_password_to_login_back_button_description
+ ))
+ }
+ },
+ actions = {
+ IconButton(
+ onClick = {
+ // Handle menu icon click
+ }
+ ) {
+ Icon(imageVector = Icons.Default.Menu, contentDescription = "Menu")
+ }
+ }
+ )
+ }
+ ) { innerPadding ->
+ Column(
+ modifier = Modifier
+// .fillMaxSize() // comment out this line to avoid keyboard overlap
+ .padding(innerPadding),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.packaging),
+ contentDescription = stringResource(id = R.string.login_logo_description),
+ modifier = Modifier
+ .size(50.dp)
+ )
+ Text(
+ text = stringResource(id = R.string.reset_password_title),
+ style = TextStyle(
+ fontSize = 30.sp,
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Light,
+ color = if (isSystemInDarkTheme()) Color.White else Color.Black
+ ),
+ modifier = Modifier
+ .wrapContentSize()
+ )
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ contentAlignment = Alignment.Center
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(
+ color = MaterialTheme.colorScheme.surfaceVariant,
+ shape = MaterialTheme.shapes.small
+ ),
+ ) {
+ // Password field and toggle button
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ // Password field
+ TextField(
+ value = password,
+ onValueChange = {
+ password = it
+ isPasswordValid = validatePassword(it)
+ doPasswordsMatch = validateConfirmPassword(password, confirmPassword)
+ },
+ isError = !isPasswordValid,
+ label = { Text(text = stringResource(id = R.string.reset_new_password_label)) },
+ singleLine = true,
+ visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
+ modifier = Modifier
+ .weight(1f)
+ .padding(start = 30.dp, end = 8.dp, bottom = 16.dp),
+ )
+
+ // Toggle button to show/hide password
+ IconButton(
+ onClick = {
+ isPasswordVisible = !isPasswordVisible
+ }
+ ) {
+ Icon(
+ painter = if (isPasswordVisible) painterResource(R.drawable.baseline_visibility_24) else painterResource(R.drawable.baseline_visibility_off_24),
+ contentDescription = if (isPasswordVisible) "Hide Password" else "Show Password",
+ modifier = Modifier
+ .padding(top = 15.dp),
+ )
+ }
+ }
+
+ // Password display error
+ if (!isPasswordValid) {
+ ErrorDisplay(text = stringResource(id = R.string.signup_password_error))
+ }
+
+ // Confirm password field and toggle button
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ // Confirm password field
+ TextField(
+ value = confirmPassword,
+ onValueChange = {
+ confirmPassword = it
+ doPasswordsMatch = validateConfirmPassword(password, it)
+ },
+ isError = !doPasswordsMatch,
+ label = { Text(text = stringResource(id = R.string.reset_confirm_new_password_label)) },
+ singleLine = true,
+ visualTransformation = if (isConfirmPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
+ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
+ modifier = Modifier
+ .weight(1f)
+ .padding(start = 30.dp, end = 8.dp, bottom = 16.dp),
+ )
+
+ // Toggle button to show/hide confirm password
+ IconButton(
+ onClick = {
+ isConfirmPasswordVisible = !isConfirmPasswordVisible
+ }
+ ) {
+ Icon(
+ painter = if (isConfirmPasswordVisible) painterResource(R.drawable.baseline_visibility_24) else painterResource(R.drawable.baseline_visibility_off_24),
+ contentDescription = if (isConfirmPasswordVisible) "Hide Confirm Password" else "Show Confirm Password",
+ modifier = Modifier
+ .padding(top = 15.dp),
+ )
+ }
+ }
+
+ // Confirm password display error
+ if (!doPasswordsMatch) {
+ ErrorDisplay(text = stringResource(id = R.string.signup_confirm_password_error))
+ }
+
+
+ // SignUp button
+ Button(
+ onClick = {
+ keyboardController?.hide()
+ // Check if all fields are valid
+ if (isPasswordValid && doPasswordsMatch) {
+ // Sign up
+ coroutineScope.launch {
+ // TODO : Call reset password function
+ }
+ }
+ },
+ modifier = Modifier
+ .padding(16.dp)
+ .width(225.dp)
+ .align(Alignment.CenterHorizontally),
+ ) {
+ Text(
+ text = stringResource(id = R.string.reset_password_submit_button).uppercase(),
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Bold,
+ )
+ )
+ }
+ }
+ }
+ }
+ }
+}
+
+// TODO: Create a function to update the password in the database
\ No newline at end of file
diff --git a/app/src/main/java/com/example/belindas_closet/screen/ScreenMain.kt b/app/src/main/java/com/example/belindas_closet/screen/ScreenMain.kt
index 20cecbc5..b3bb029f 100644
--- a/app/src/main/java/com/example/belindas_closet/screen/ScreenMain.kt
+++ b/app/src/main/java/com/example/belindas_closet/screen/ScreenMain.kt
@@ -37,6 +37,9 @@ fun ScreenMain() {
composable(Routes.ForgotPassword.route) {
ForgotPasswordPage(navController = navController)
}
+ composable(Routes.ResetPassword.route) {
+ ResetPasswordPage(navController = navController)
+ }
composable(Routes.AdminView.route) {
AdminView(navController = navController)
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index eb10f18b..d60a3df9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -67,4 +67,12 @@
Donation Info
-
\ No newline at end of file
+
+
+ Reset Password
+ New Password
+ New password is invalid, please try again!
+ Confirm New Password
+ Reset Password
+ Back to Login
+