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
This commit is contained in:
Yogesh Choudhary Paliyal
2023-05-10 23:11:41 +05:30
committed by GitHub
parent bde4f09e84
commit 5381938454
23 changed files with 302 additions and 236 deletions

View File

@@ -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) {

View File

@@ -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),

View File

@@ -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<Action>.updateState(state: ChangeAppPasswordState) {
this(StateUpdateAction(state = state))
}
@Composable
fun ChangePassword(state: ChangeAppPasswordState) {
val dispatchAction = rememberTypedDispatcher<Action>()
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))
}
}
}
}
}
}

View File

@@ -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 -> {
}
}

View File

@@ -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
)

View File

@@ -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)

View File

@@ -92,5 +92,13 @@
<string name="incorrect_password">गलत पासवर्ड</string>
<string name="password_no_match">पासवर्ड मेल नहीं खाता</string>
<string name="auto_backup_desc">जब भी खाता जोड़ा या संशोधित किया जाएगा, आपके खाते का बैकअप ले लिया जाएगा</string>
<string name="change_app_password">ऐप पासवर्ड बदलें</string>
<string name="old_password">पुराना पासवर्ड</string>
<string name="new_password">नया पासवर्ड</string>
<string name="blank_old_password">कृपया अपना पुराना पासवर्ड दर्ज करें</string>
<string name="incorrect_old_password">कृपया अपना सही पुराना पासवर्ड दर्ज करें</string>
<string name="blank_new_password">कृपया अपना नया पासवर्ड दर्ज करें</string>
<string name="blank_confirm_password">कृपया पुष्टि पासवर्ड दर्ज करें</string>
<string name="password_change_success">पासवर्ड सफलतापूर्वक बदला गया</string>
</resources>

View File

@@ -90,5 +90,13 @@
<string name="incorrect_password">Senha incorreta</string>
<string name="password_no_match">A senha não corresponde</string>
<string name="auto_backup_desc">Será feito backup de suas contas sempre que uma conta for adicionada ou modificada</string>
<string name="change_app_password">Alterar senha do aplicativo</string>
<string name="old_password">Senha Antiga</string>
<string name="new_password">Nova Senha</string>
<string name="blank_old_password">Por favor, digite sua senha antiga</string>
<string name="incorrect_old_password">Digite sua senha antiga correta</string>
<string name="blank_new_password">Por favor, digite sua nova senha</string>
<string name="blank_confirm_password">Por favor, digite a senha de confirmação</string>
<string name="password_change_success">Senha alterada com sucesso</string>
</resources>

View File

@@ -91,5 +91,13 @@
<string name="incorrect_password">密码错误</string>
<string name="password_no_match">密码不匹配</string>
<string name="auto_backup_desc">每当添加或修改帐户时,都会备份您的帐户</string>
<string name="change_app_password">更改应用密码</string>
<string name="old_password">旧密码</string>
<string name="new_password">新密码</string>
<string name="blank_old_password">请输入您的旧密码</string>
<string name="incorrect_old_password">请输入正确的旧密码</string>
<string name="blank_new_password">请输入您的新密码</string>
<string name="blank_confirm_password">请输入确认密码</string>
<string name="password_change_success">密码修改成功</string>
</resources>

View File

@@ -90,5 +90,13 @@
<string name="incorrect_password">Incorrect Password</string>
<string name="password_no_match">The password did not match</string>
<string name="auto_backup_desc">Your accounts will be backed up whenever account is added or modified</string>
<string name="change_app_password">Change App Password</string>
<string name="old_password">Old Password</string>
<string name="new_password">New Password</string>
<string name="blank_old_password">Please enter your old password</string>
<string name="incorrect_old_password">Please enter your correct old password</string>
<string name="blank_new_password">Please enter your new password</string>
<string name="blank_confirm_password">Please enter confirm password</string>
<string name="password_change_success">Password changed successfully</string>
</resources>