From 5381938454d2ae716c22455b26f7807ca85072cd Mon Sep 17 00:00:00 2001 From: Yogesh Choudhary Paliyal Date: Wed, 10 May 2023 23:11:41 +0530 Subject: [PATCH] Password change screen implementation (#534) * kmp migration started: shared module added * Drop files from .gitignore * Drop files from .gitignore * Drop files from .gitignore * Drop files from .gitignore * Drop files from .gitignore * Drop files from .gitignore * Drop files from .gitignore * Drop files from .gitignore * add password change screen * add password change screen * add password change screen * Drop files from .gitignore * merged --- .gitignore | 2 +- .idea/.gitignore | 3 - .../artifacts/common_desktop_1_0_SNAPSHOT.xml | 8 - .idea/artifacts/desktop_jvm_1_0_SNAPSHOT.xml | 8 - .idea/artifacts/shared_desktop.xml | 8 - .idea/artifacts/shared_desktop_1_0.xml | 8 - .../artifacts/shared_desktop_1_0_SNAPSHOT.xml | 8 - .idea/deploymentTargetDropDown.xml | 17 -- .idea/gradle.xml | 20 -- .idea/kotlinc.xml | 6 - .idea/misc.xml | 13 - .idea/uiDesigner.xml | 124 --------- .idea/vcs.xml | 6 - .../keypass/ui/auth/AuthScreen.kt | 10 +- .../ui/auth/components/PasswordInputField.kt | 3 +- .../ui/changePassword/ChangePassword.kt | 235 ++++++++++++++++++ .../ui/nav/DashboardComposeActivity.kt | 5 + .../ui/redux/states/ChangeAppPasswordState.kt | 15 ++ .../keypass/ui/settings/MySettingsFragment.kt | 7 + app/src/main/res/values-hi/strings.xml | 8 + app/src/main/res/values-pt-rBR/strings.xml | 8 + app/src/main/res/values-zh-rCN/strings.xml | 8 + app/src/main/res/values/strings.xml | 8 + 23 files changed, 302 insertions(+), 236 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/artifacts/common_desktop_1_0_SNAPSHOT.xml delete mode 100644 .idea/artifacts/desktop_jvm_1_0_SNAPSHOT.xml delete mode 100644 .idea/artifacts/shared_desktop.xml delete mode 100644 .idea/artifacts/shared_desktop_1_0.xml delete mode 100644 .idea/artifacts/shared_desktop_1_0_SNAPSHOT.xml delete mode 100644 .idea/deploymentTargetDropDown.xml delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/kotlinc.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/uiDesigner.xml delete mode 100644 .idea/vcs.xml create mode 100644 app/src/main/java/com/yogeshpaliyal/keypass/ui/changePassword/ChangePassword.kt create mode 100644 app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/states/ChangeAppPasswordState.kt diff --git a/.gitignore b/.gitignore index 81d60144..89b85ca6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ build/ *.bin ### IntelliJ IDEA ### -.idea/modules.xml +.idea .idea/jarRepositories.xml .idea/compiler.xml .idea/libraries/ diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/artifacts/common_desktop_1_0_SNAPSHOT.xml b/.idea/artifacts/common_desktop_1_0_SNAPSHOT.xml deleted file mode 100644 index 24e82828..00000000 --- a/.idea/artifacts/common_desktop_1_0_SNAPSHOT.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/shared/common/build/libs - - - - - \ No newline at end of file diff --git a/.idea/artifacts/desktop_jvm_1_0_SNAPSHOT.xml b/.idea/artifacts/desktop_jvm_1_0_SNAPSHOT.xml deleted file mode 100644 index 6cfd400f..00000000 --- a/.idea/artifacts/desktop_jvm_1_0_SNAPSHOT.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/desktop/build/libs - - - - - \ No newline at end of file diff --git a/.idea/artifacts/shared_desktop.xml b/.idea/artifacts/shared_desktop.xml deleted file mode 100644 index 806a6529..00000000 --- a/.idea/artifacts/shared_desktop.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/shared/build/libs - - - - - \ No newline at end of file diff --git a/.idea/artifacts/shared_desktop_1_0.xml b/.idea/artifacts/shared_desktop_1_0.xml deleted file mode 100644 index d164c91b..00000000 --- a/.idea/artifacts/shared_desktop_1_0.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/shared/build/libs - - - - - \ No newline at end of file diff --git a/.idea/artifacts/shared_desktop_1_0_SNAPSHOT.xml b/.idea/artifacts/shared_desktop_1_0_SNAPSHOT.xml deleted file mode 100644 index 52fdce32..00000000 --- a/.idea/artifacts/shared_desktop_1_0_SNAPSHOT.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - $PROJECT_DIR$/shared/build/libs - - - - - \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index 4027a290..00000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index b03e9996..00000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml deleted file mode 100644 index 0fc31131..00000000 --- a/.idea/kotlinc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 1e382762..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index 2b63946d..00000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddf..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/AuthScreen.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/AuthScreen.kt index 4f122294..8e42d149 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/AuthScreen.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/AuthScreen.kt @@ -76,11 +76,11 @@ fun AuthScreen(state: AuthState) { Text(text = stringResource(id = state.title)) PasswordInputField( - password, - setPassword, - passwordVisible, - setPasswordVisible, - passwordError + password = password, + setPassword = setPassword, + passwordVisible = passwordVisible, + setPasswordVisible = setPasswordVisible, + passwordError = passwordError ) ButtonBar(state, password, setPasswordError) { diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/components/PasswordInputField.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/components/PasswordInputField.kt index bd2e2828..66a5897b 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/components/PasswordInputField.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/auth/components/PasswordInputField.kt @@ -20,6 +20,7 @@ import com.yogeshpaliyal.keypass.R @Composable fun PasswordInputField( + label: Int = R.string.enter_password, password: String, setPassword: (String) -> Unit, passwordVisible: Boolean, @@ -31,7 +32,7 @@ fun PasswordInputField( value = password, singleLine = true, placeholder = { - Text(text = stringResource(id = R.string.enter_password)) + Text(text = stringResource(id = label)) }, visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/changePassword/ChangePassword.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/changePassword/ChangePassword.kt new file mode 100644 index 00000000..a7e7c4cd --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/changePassword/ChangePassword.kt @@ -0,0 +1,235 @@ +package com.yogeshpaliyal.keypass.ui.changePassword + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +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.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ArrowBackIosNew +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.yogeshpaliyal.common.utils.getKeyPassPassword +import com.yogeshpaliyal.common.utils.setKeyPassPassword +import com.yogeshpaliyal.keypass.R +import com.yogeshpaliyal.keypass.ui.auth.components.PasswordInputField +import com.yogeshpaliyal.keypass.ui.redux.actions.Action +import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction +import com.yogeshpaliyal.keypass.ui.redux.actions.StateUpdateAction +import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction +import com.yogeshpaliyal.keypass.ui.redux.states.ChangeAppPasswordState +import kotlinx.coroutines.launch +import org.reduxkotlin.TypedDispatcher +import org.reduxkotlin.compose.rememberTypedDispatcher + +fun TypedDispatcher.updateState(state: ChangeAppPasswordState) { + this(StateUpdateAction(state = state)) +} + +@Composable +fun ChangePassword(state: ChangeAppPasswordState) { + val dispatchAction = rememberTypedDispatcher() + + val coroutineScope = rememberCoroutineScope() + val context = LocalContext.current + + Scaffold(bottomBar = { + BottomAppBar { + IconButton(onClick = { + dispatchAction(GoBackAction) + }) { + Icon( + painter = rememberVectorPainter(image = Icons.Rounded.ArrowBackIosNew), + contentDescription = "Go Back", + tint = MaterialTheme.colorScheme.onSurface + ) + } + } + }) { contentPadding -> + Surface(modifier = Modifier.padding(contentPadding)) { + Column( + modifier = Modifier + .padding(32.dp) + .fillMaxSize(1f) + .verticalScroll(rememberScrollState()), + Arrangement.SpaceEvenly, + Alignment.CenterHorizontally + ) { + Image( + painter = painterResource(R.drawable.ic_undraw_unlock_24mb), + contentDescription = "" + ) + + Text(text = stringResource(id = R.string.change_app_password)) + + PasswordInputField( + R.string.old_password, + state.oldPassword.password, + { + dispatchAction.updateState( + state.copy( + oldPassword = state.oldPassword.copy( + password = it, + passwordError = null + ) + ) + ) + }, + state.oldPassword.passwordVisible, + { + dispatchAction.updateState( + state.copy( + oldPassword = state.oldPassword.copy( + passwordVisible = it + ) + ) + ) + }, + state.oldPassword.passwordError + ) + + PasswordInputField( + R.string.new_password, + state.newPassword.password, + { + dispatchAction.updateState( + state.copy( + newPassword = state.newPassword.copy( + password = it, + passwordError = null + ) + ) + ) + }, + state.newPassword.passwordVisible, + { + dispatchAction.updateState( + state.copy( + newPassword = state.newPassword.copy( + passwordVisible = it + ) + ) + ) + }, + state.newPassword.passwordError + ) + + PasswordInputField( + R.string.confirm_password, + state.confirmPassword.password, + { + dispatchAction.updateState( + state.copy( + confirmPassword = state.confirmPassword.copy( + password = it, + passwordError = null + ) + ) + ) + }, + state.confirmPassword.passwordVisible, + { + dispatchAction.updateState( + state.copy( + confirmPassword = state.confirmPassword.copy( + passwordVisible = it + ) + ) + ) + }, + state.confirmPassword.passwordError + ) + + Row(modifier = Modifier.fillMaxWidth(1f), Arrangement.SpaceEvenly) { + Button(onClick = { + // Validate password and change + val oldPassword = state.oldPassword + if (oldPassword.password.isBlank()) { + dispatchAction.updateState( + state.copy( + oldPassword = oldPassword.copy( + passwordError = R.string.blank_old_password + ) + ) + ) + return@Button + } + + val newPassword = state.newPassword + if (newPassword.password.isBlank()) { + dispatchAction.updateState( + state.copy( + newPassword = newPassword.copy( + passwordError = R.string.blank_new_password + ) + ) + ) + return@Button + } + + val confirmPassword = state.confirmPassword + if (confirmPassword.password.isBlank()) { + dispatchAction.updateState( + state.copy( + confirmPassword = confirmPassword.copy( + passwordError = R.string.blank_confirm_password + ) + ) + ) + return@Button + } + + coroutineScope.launch { + val oldPasswordFromStore = context.getKeyPassPassword() + if (oldPassword.password != oldPasswordFromStore) { + dispatchAction.updateState( + state.copy( + oldPassword = oldPassword.copy( + passwordError = R.string.incorrect_old_password + ) + ) + ) + return@launch + } + + if (newPassword.password != confirmPassword.password) { + dispatchAction.updateState( + state.copy( + confirmPassword = confirmPassword.copy( + passwordError = R.string.password_no_match + ) + ) + ) + return@launch + } + + context.setKeyPassPassword(newPassword.password) + dispatchAction(ToastAction(R.string.password_change_success)) + } + }) { + Text(text = stringResource(id = R.string.change_app_password)) + } + } + } + } + } +} diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt index 11ee10b6..7669ff82 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.unit.dp import com.yogeshpaliyal.keypass.BuildConfig import com.yogeshpaliyal.keypass.ui.auth.AuthScreen import com.yogeshpaliyal.keypass.ui.backup.BackupScreen +import com.yogeshpaliyal.keypass.ui.changePassword.ChangePassword import com.yogeshpaliyal.keypass.ui.detail.AccountDetailPage import com.yogeshpaliyal.keypass.ui.home.Homepage import com.yogeshpaliyal.keypass.ui.redux.KeyPassRedux @@ -61,6 +62,7 @@ import com.yogeshpaliyal.keypass.ui.redux.states.AccountDetailState import com.yogeshpaliyal.keypass.ui.redux.states.AuthState import com.yogeshpaliyal.keypass.ui.redux.states.BackupScreenState import com.yogeshpaliyal.keypass.ui.redux.states.BottomSheetState +import com.yogeshpaliyal.keypass.ui.redux.states.ChangeAppPasswordState import com.yogeshpaliyal.keypass.ui.redux.states.HomeState import com.yogeshpaliyal.keypass.ui.redux.states.KeyPassState import com.yogeshpaliyal.keypass.ui.redux.states.ScreenState @@ -157,6 +159,9 @@ fun CurrentPage() { BackupScreen(state = it) } + is ChangeAppPasswordState -> { + ChangePassword(it) + } is TotpDetailState -> { } } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/states/ChangeAppPasswordState.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/states/ChangeAppPasswordState.kt new file mode 100644 index 00000000..c6556f45 --- /dev/null +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/redux/states/ChangeAppPasswordState.kt @@ -0,0 +1,15 @@ +package com.yogeshpaliyal.keypass.ui.redux.states + +import androidx.annotation.StringRes + +data class ChangeAppPasswordState( + val oldPassword: PasswordFieldState = PasswordFieldState(), + val newPassword: PasswordFieldState = PasswordFieldState(), + val confirmPassword: PasswordFieldState = PasswordFieldState() +) : ScreenState(false) + +data class PasswordFieldState( + val password: String = "", + val passwordVisible: Boolean = false, + @StringRes val passwordError: Int? = null +) diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/settings/MySettingsFragment.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/settings/MySettingsFragment.kt index 438c9981..f357174a 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/settings/MySettingsFragment.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/settings/MySettingsFragment.kt @@ -46,6 +46,7 @@ import com.yogeshpaliyal.keypass.ui.redux.actions.IntentNavigation import com.yogeshpaliyal.keypass.ui.redux.actions.NavigationAction import com.yogeshpaliyal.keypass.ui.redux.actions.ToastAction import com.yogeshpaliyal.keypass.ui.redux.states.BackupScreenState +import com.yogeshpaliyal.keypass.ui.redux.states.ChangeAppPasswordState import kotlinx.coroutines.launch import org.reduxkotlin.compose.rememberTypedDispatcher @@ -155,6 +156,12 @@ fun MySettingCompose() { ) { launcher.launch(arrayOf()) } + PreferenceItem( + title = R.string.change_app_password, + summary = R.string.change_app_password + ) { + dispatchAction(NavigationAction(ChangeAppPasswordState())) + } Divider( modifier = Modifier .fillMaxWidth(1f) diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index bd1b3d09..61de1882 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -92,5 +92,13 @@ गलत पासवर्ड पासवर्ड मेल नहीं खाता जब भी खाता जोड़ा या संशोधित किया जाएगा, आपके खाते का बैकअप ले लिया जाएगा + ऐप पासवर्ड बदलें + पुराना पासवर्ड + नया पासवर्ड + कृपया अपना पुराना पासवर्ड दर्ज करें + कृपया अपना सही पुराना पासवर्ड दर्ज करें + कृपया अपना नया पासवर्ड दर्ज करें + कृपया पुष्टि पासवर्ड दर्ज करें + पासवर्ड सफलतापूर्वक बदला गया \ No newline at end of file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 32ce2897..1e317d48 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -90,5 +90,13 @@ Senha incorreta A senha não corresponde Será feito backup de suas contas sempre que uma conta for adicionada ou modificada + Alterar senha do aplicativo + Senha Antiga + Nova Senha + Por favor, digite sua senha antiga + Digite sua senha antiga correta + Por favor, digite sua nova senha + Por favor, digite a senha de confirmação + Senha alterada com sucesso diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c1767f05..37ebfcb6 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -91,5 +91,13 @@ 密码错误 密码不匹配 每当添加或修改帐户时,都会备份您的帐户 + 更改应用密码 + 旧密码 + 新密码 + 请输入您的旧密码 + 请输入正确的旧密码 + 请输入您的新密码 + 请输入确认密码 + 密码修改成功 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 30df2dd8..776df4a6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -90,5 +90,13 @@ Incorrect Password The password did not match Your accounts will be backed up whenever account is added or modified + Change App Password + Old Password + New Password + Please enter your old password + Please enter your correct old password + Please enter your new password + Please enter confirm password + Password changed successfully