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