diff --git a/build.gradle.kts b/build.gradle.kts index 325bf54..deb7f92 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -78,13 +78,29 @@ compose.desktop { mainClass = "MainKt" nativeDistributions { + includeAllModules = true targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "SecVault" packageVersion = "1.0.0" + + description = "A secure vault application for managing encrypted data." + vendor = "Shade Dev" + copyright = "© 2024 Shade Dev. All rights reserved." + windows { menuGroup = "SecVault" - upgradeUuid = "f9ccedd2-ad1d-4e25-b0ab-830c83259222" + shortcut = true + perUserInstall = false + } + + macOS { + dockName = "SecVault" + } + + linux { + shortcut = true } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/core/security/AuthenticationManager.kt b/src/main/kotlin/core/security/AuthenticationManager.kt index 5ceccde..3a042f9 100644 --- a/src/main/kotlin/core/security/AuthenticationManager.kt +++ b/src/main/kotlin/core/security/AuthenticationManager.kt @@ -33,7 +33,7 @@ class AuthenticationManager( Result.Success(user) } } else { - result + Result.Error("Invalid username or password") } } } diff --git a/src/main/kotlin/ui/components/FormScreenComponents.kt b/src/main/kotlin/ui/components/FormScreenComponents.kt index 26e9810..89654fb 100644 --- a/src/main/kotlin/ui/components/FormScreenComponents.kt +++ b/src/main/kotlin/ui/components/FormScreenComponents.kt @@ -1,6 +1,8 @@ package ui.components -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import cafe.adriel.voyager.navigator.Navigator import core.models.UiState import repository.user.User @@ -10,10 +12,7 @@ import ui.components.forms.authentication.RegisterForm import ui.screens.ForgotPasswordScreen import ui.screens.LoginScreen import ui.screens.RegisterScreen -import ui.validators.ForgotPasswordFieldName -import ui.validators.RegisterFieldName -import ui.validators.forgotPasswordFormValidator -import ui.validators.registerFormValidator +import ui.validators.* import viewmodel.ForgotPasswordScreenModel import viewmodel.LoginScreenModel import viewmodel.RegisterScreenModel @@ -25,19 +24,28 @@ fun LoginScreenContent( loginState: UiState ) { - var username by remember { mutableStateOf("") } - var password by remember { mutableStateOf("") } - var masterPassword by remember { mutableStateOf("") } + val formValidator = remember { loginFormValidator() } + + val username = formValidator.getField(LoginFormFieldName.USERNAME) + val password = formValidator.getField(LoginFormFieldName.PASSWORD) + val masterPassword = formValidator.getField(LoginFormFieldName.MASTER_PASSWORD) + + val isFormValid by formValidator.isValid LoginForm( username = username, - onUsernameChange = { username = it }, password = password, - onPasswordChange = { password = it }, masterPassword = masterPassword, - onMasterPassword = { masterPassword = it }, + isFormValid = isFormValid, + formValidator = formValidator, loginState = loginState, - onLoginClick = { screenModel.login(username, password, masterPassword) }, + onLoginClick = { + screenModel.login( + username!!.value.value, + password!!.value.value, + masterPassword!!.value.value, + ) + }, onForgotPasswordClick = { navigator?.push(ForgotPasswordScreen()) }, onRegisterClick = { if (navigator?.canPop == true) navigator.pop() else navigator?.push(RegisterScreen()) diff --git a/src/main/kotlin/ui/components/forms/authentication/LoginForm.kt b/src/main/kotlin/ui/components/forms/authentication/LoginForm.kt index b696f7b..255c4a1 100644 --- a/src/main/kotlin/ui/components/forms/authentication/LoginForm.kt +++ b/src/main/kotlin/ui/components/forms/authentication/LoginForm.kt @@ -19,6 +19,8 @@ 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.sp +import core.form.FormField +import core.form.validation.FormValidator import core.models.UiState import repository.user.User import ui.components.CloseButton @@ -28,15 +30,15 @@ import ui.components.PasswordTextField import ui.theme.Font import ui.theme.secondary import ui.theme.tertiary +import ui.validators.LoginFormFieldName @Composable fun LoginForm( - username: String, - onUsernameChange: (String) -> Unit, - password: String, - onPasswordChange: (String) -> Unit, - masterPassword: String, - onMasterPassword: (String) -> Unit, + username: FormField?, + password: FormField?, + masterPassword: FormField?, + formValidator: FormValidator, + isFormValid: Boolean, loginState: UiState, onLoginClick: () -> Unit, onForgotPasswordClick: () -> Unit, @@ -84,25 +86,76 @@ fun LoginForm( textAlign = TextAlign.Center, ) Spacer(modifier = Modifier.height(10.dp)) - FormTextField( - value = username, - onValueChange = onUsernameChange, - label = "Username", - icon = Icons.Filled.AccountCircle, - modifier = Modifier.height(40.dp).width(360.dp) - ) - PasswordTextField( - value = password, - onValueChange = onPasswordChange, - label = "Password", - modifier = Modifier.height(40.dp).width(360.dp) - ) - PasswordTextField( - value = masterPassword, - onValueChange = onMasterPassword, - label = "Master Password", - modifier = Modifier.height(40.dp).width(360.dp) - ) + Column( + verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.Start + ) { + FormTextField( + value = username?.value?.value ?: "", + onValueChange = { newValue -> + username?.value?.value = newValue + formValidator.validateField(LoginFormFieldName.USERNAME) + }, + label = "Username", + icon = Icons.Filled.AccountCircle, + modifier = Modifier.height(40.dp).width(360.dp) + ) + username?.error?.value?.let { + Text( + text = it, + color = Color.Red, + fontFamily = Font.RobotoRegular, + fontSize = 10.sp, + modifier = Modifier.padding(start = 8.dp) + ) + } + } + Column( + verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.Start + ) { + PasswordTextField( + value = password?.value?.value ?: "", + onValueChange = { newValue -> + password?.value?.value = newValue + formValidator.validateField(LoginFormFieldName.PASSWORD) + }, + label = "Password", + modifier = Modifier.height(40.dp).width(360.dp) + ) + password?.error?.value?.let { + Text( + text = it, + color = Color.Red, + fontFamily = Font.RobotoRegular, + fontSize = 10.sp, + modifier = Modifier.padding(start = 8.dp) + ) + } + } + Column( + verticalArrangement = Arrangement.spacedBy(2.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.Start + ) { + PasswordTextField( + value = masterPassword?.value?.value ?: "", + onValueChange = { newValue -> + masterPassword?.value?.value = newValue + formValidator.validateField(LoginFormFieldName.MASTER_PASSWORD) + }, + label = "Master Password", + modifier = Modifier.height(40.dp).width(360.dp) + ) + masterPassword?.error?.value?.let { + Text( + text = it, + color = Color.Red, + fontFamily = Font.RobotoRegular, + fontSize = 10.sp, + modifier = Modifier.padding(start = 8.dp) + ) + } + } Row( horizontalArrangement = Arrangement.Start, modifier = Modifier.width(360.dp).height(25.dp) @@ -124,7 +177,7 @@ fun LoginForm( } Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { Button( - enabled = loginState !is UiState.Loading, + enabled = loginState !is UiState.Loading && isFormValid, onClick = onLoginClick, modifier = Modifier.width(175.dp), colors = ButtonColors( @@ -136,6 +189,7 @@ fun LoginForm( ) { Text( + color = Color.White, text = "Login", fontStyle = FontStyle.Normal, fontWeight = FontWeight.Normal, diff --git a/src/main/kotlin/ui/validators/LoginFormValidator.kt b/src/main/kotlin/ui/validators/LoginFormValidator.kt new file mode 100644 index 0000000..a6b374f --- /dev/null +++ b/src/main/kotlin/ui/validators/LoginFormValidator.kt @@ -0,0 +1,35 @@ +package ui.validators + +import core.form.FormField +import core.form.FormFieldName +import core.form.validation.FormValidator +import core.form.validation.Validator +import core.form.validation.notNullRule + +fun loginFormValidator(): FormValidator { + return FormValidator() + .addField( + LoginFormFieldName.USERNAME, FormField( + validator = Validator() + .addRule(notNullRule(LoginFormFieldName.USERNAME.fieldName)) + ) + ) + .addField( + LoginFormFieldName.PASSWORD, FormField( + validator = Validator() + .addRule(notNullRule(LoginFormFieldName.PASSWORD.fieldName)) + ) + ) + .addField( + LoginFormFieldName.MASTER_PASSWORD, FormField( + validator = Validator() + .addRule(notNullRule(LoginFormFieldName.MASTER_PASSWORD.fieldName)) + ) + ).validateAllFields() +} + +enum class LoginFormFieldName(val fieldName: String) : FormFieldName { + USERNAME("Username"), + PASSWORD("Password"), + MASTER_PASSWORD("Master Password"), +} \ No newline at end of file