Add change default password length setting (#599)

* Add change default password length setting

* Add a localized summary for preference item

* Add saving password length after changing it on the generation

---------

Co-authored-by: kochetov <kochetov@alkor.co.ru>
This commit is contained in:
Vladislav Kochetov
2023-06-02 21:54:27 -06:00
committed by GitHub
parent e7c748114a
commit 160a67e579
40 changed files with 371 additions and 31 deletions

View File

@@ -0,0 +1,106 @@
package com.yogeshpaliyal.keypass.ui.changeDefaultPasswordLength
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBackIosNew
import androidx.compose.material.icons.rounded.Done
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.FloatingActionButton
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.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.yogeshpaliyal.keypass.ui.generate.ui.components.PasswordLengthInput
import com.yogeshpaliyal.keypass.ui.redux.actions.Action
import com.yogeshpaliyal.keypass.ui.redux.actions.GoBackAction
import com.yogeshpaliyal.keypass.ui.redux.states.ChangeDefaultPasswordLengthState
import org.reduxkotlin.TypedDispatcher
import org.reduxkotlin.compose.rememberTypedDispatcher
@Composable
fun ChangeDefaultPasswordLengthScreen(
viewModel: ChangeDefaultPasswordLengthViewModel = viewModel()
) {
viewModel.retrieveSavedPasswordLength(LocalContext.current)
val dispatchAction = rememberTypedDispatcher<Action>()
val state by viewModel.viewState.collectAsState()
Scaffold(bottomBar = { BottomBar(dispatchAction, viewModel) }) { contentPadding ->
Surface(
modifier = Modifier
.padding(contentPadding)
.fillMaxWidth()
) {
ChangeDefaultPasswordLengthContent(state = state, viewModel = viewModel)
}
}
}
@Composable
private fun ChangeDefaultPasswordLengthContent(
state: ChangeDefaultPasswordLengthState,
viewModel: ChangeDefaultPasswordLengthViewModel
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
PasswordLengthInput(length = state.length, viewModel::onPasswordLengthChanged)
}
}
@Composable
private fun BottomBar(
dispatchAction: TypedDispatcher<Action>,
viewModel: ChangeDefaultPasswordLengthViewModel
) {
val context = LocalContext.current
BottomAppBar(
actions = {
IconButton(onClick = { dispatchAction(GoBackAction) }) {
Icon(
painter = rememberVectorPainter(image = Icons.Rounded.ArrowBackIosNew),
contentDescription = "Go Back",
tint = MaterialTheme.colorScheme.onSurface
)
}
},
floatingActionButton = {
FloatingActionButton(modifier = Modifier.testTag("save"), onClick = {
// Save new password length
viewModel.updatePasswordLength(context) {
// Close screen
dispatchAction(GoBackAction)
}
}) {
Icon(
painter = rememberVectorPainter(image = Icons.Rounded.Done),
contentDescription = "Save Changes"
)
}
}
)
}
@Preview(name = "ChangeDefaultPasswordLength", showBackground = true, showSystemUi = true)
@Composable
fun ChangeDefaultPasswordLengthPreview() {
ChangeDefaultPasswordLengthScreen()
}

View File

@@ -0,0 +1,53 @@
package com.yogeshpaliyal.keypass.ui.changeDefaultPasswordLength
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yogeshpaliyal.common.utils.getKeyPassPasswordLength
import com.yogeshpaliyal.common.utils.setKeyPassPasswordLength
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
import com.yogeshpaliyal.keypass.ui.redux.states.ChangeDefaultPasswordLengthState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
class ChangeDefaultPasswordLengthViewModel : ViewModel() {
private val _viewState = MutableStateFlow(ChangeDefaultPasswordLengthState())
val viewState = _viewState.asStateFlow()
/**
* Initial [ChangeDefaultPasswordLengthState] with previously saved length
* */
fun retrieveSavedPasswordLength(context: Context) {
viewModelScope.launch {
_viewState.update {
val oldPasswordLength =
context.getKeyPassPasswordLength() ?: DEFAULT_PASSWORD_LENGTH
ChangeDefaultPasswordLengthState(length = oldPasswordLength)
}
}
}
/**
* Stores the new password length from [_viewState] in the data store [Context.setKeyPassPasswordLength]
* */
fun updatePasswordLength(context: Context, callback: () -> Unit) {
viewModelScope.launch {
_viewState.value.length.let { length ->
context.setKeyPassPasswordLength(length)
callback.invoke()
}
}
}
/**
* Updates the state after changing the value of the slider
* */
fun onPasswordLengthChanged(value: Float) {
_viewState.update {
_viewState.value.copy(length = value)
}
}
}

View File

@@ -14,6 +14,7 @@ class GeneratePasswordActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.retrieveSavedPasswordLength(baseContext)
setContent {
Mdc3Theme {
GeneratePasswordScreen(viewModel)

View File

@@ -1,24 +1,49 @@
package com.yogeshpaliyal.keypass.ui.generate
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yogeshpaliyal.common.utils.PasswordGenerator
import com.yogeshpaliyal.common.utils.getKeyPassPasswordLength
import com.yogeshpaliyal.common.utils.setKeyPassPasswordLength
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class GeneratePasswordViewModel @Inject constructor() : ViewModel() {
class GeneratePasswordViewModel @Inject constructor(
@ApplicationContext context: Context
) : ViewModel() {
private val _viewState = MutableStateFlow(GeneratePasswordViewState.Initial)
val viewState = _viewState.asStateFlow()
init {
observeState(context)
}
fun retrieveSavedPasswordLength(context: Context) {
viewModelScope.launch {
val savedPasswordLength = context.getKeyPassPasswordLength() ?: DEFAULT_PASSWORD_LENGTH
_viewState.update {
_viewState.value.copy(length = savedPasswordLength)
}
}
}
fun generatePassword() {
val currentViewState = _viewState.value
val passwordGenerator = PasswordGenerator(
length = currentViewState.length,
length = currentViewState.length.toInt(),
includeUpperCaseLetters = currentViewState.includeUppercaseLetters,
includeLowerCaseLetters = currentViewState.includeLowercaseLetters,
includeSymbols = currentViewState.includeSymbols,
@@ -33,7 +58,7 @@ class GeneratePasswordViewModel @Inject constructor() : ViewModel() {
fun onPasswordLengthSliderChange(value: Float) {
_viewState.update {
it.copy(length = value.toInt())
it.copy(length = value)
}
}
@@ -60,4 +85,16 @@ class GeneratePasswordViewModel @Inject constructor() : ViewModel() {
it.copy(includeSymbols = checked)
}
}
@OptIn(FlowPreview::class)
private fun observeState(context: Context) {
viewModelScope.launch {
// Save every changed value from password length with a delay
_viewState
.debounce(400)
.collectLatest { state ->
context.setKeyPassPasswordLength(state.length)
}
}
}
}

View File

@@ -1,7 +1,9 @@
package com.yogeshpaliyal.keypass.ui.generate
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
data class GeneratePasswordViewState(
val length: Int,
val length: Float,
val includeUppercaseLetters: Boolean,
val includeLowercaseLetters: Boolean,
val includeSymbols: Boolean,
@@ -10,7 +12,7 @@ data class GeneratePasswordViewState(
) {
companion object {
val Initial = GeneratePasswordViewState(
length = 10,
length = DEFAULT_PASSWORD_LENGTH,
includeUppercaseLetters = true,
includeLowercaseLetters = true,
includeSymbols = true,

View File

@@ -17,7 +17,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -26,6 +25,7 @@ import androidx.compose.ui.unit.dp
import com.google.accompanist.themeadapter.material3.Mdc3Theme
import com.yogeshpaliyal.keypass.ui.generate.GeneratePasswordViewState
import com.yogeshpaliyal.keypass.ui.generate.ui.components.CheckboxWithLabel
import com.yogeshpaliyal.keypass.ui.generate.ui.components.PasswordLengthInput
@Composable
fun GeneratePasswordContent(
@@ -135,21 +135,6 @@ private fun PasswordTextField(
)
}
@Composable
private fun PasswordLengthInput(
length: Int,
onPasswordLengthChange: (Float) -> Unit
) {
Text(text = "Password Length: $length")
Slider(
value = length.toFloat(),
onValueChange = onPasswordLengthChange,
valueRange = 7f..50f,
steps = 43
)
}
@Composable
private fun UppercaseAlphabetInput(
includeUppercaseLetters: Boolean,

View File

@@ -0,0 +1,22 @@
package com.yogeshpaliyal.keypass.ui.generate.ui.components
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
const val DEFAULT_PASSWORD_LENGTH = 10f
@Composable
fun PasswordLengthInput(
length: Float,
onPasswordLengthChange: (Float) -> Unit
) {
Text(text = "Password Length: ${length.toInt()}")
Slider(
value = length,
onValueChange = onPasswordLengthChange,
valueRange = 7f..50f,
steps = 43
)
}

View File

@@ -51,6 +51,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.changeDefaultPasswordLength.ChangeDefaultPasswordLengthScreen
import com.yogeshpaliyal.keypass.ui.changePassword.ChangePassword
import com.yogeshpaliyal.keypass.ui.detail.AccountDetailPage
import com.yogeshpaliyal.keypass.ui.home.Homepage
@@ -64,6 +65,7 @@ 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.ChangeDefaultPasswordLengthState
import com.yogeshpaliyal.keypass.ui.redux.states.HomeState
import com.yogeshpaliyal.keypass.ui.redux.states.KeyPassState
import com.yogeshpaliyal.keypass.ui.redux.states.ScreenState
@@ -163,6 +165,11 @@ fun CurrentPage() {
is ChangeAppPasswordState -> {
ChangePassword(it)
}
is ChangeDefaultPasswordLengthState -> {
ChangeDefaultPasswordLengthScreen()
}
is TotpDetailState -> {
}
}

View File

@@ -0,0 +1,7 @@
package com.yogeshpaliyal.keypass.ui.redux.states
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
data class ChangeDefaultPasswordLengthState(
val length: Float = DEFAULT_PASSWORD_LENGTH
) : ScreenState(false)

View File

@@ -34,9 +34,11 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
@@ -48,9 +50,11 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.yogeshpaliyal.common.utils.BACKUP_KEY_LENGTH
import com.yogeshpaliyal.common.utils.email
import com.yogeshpaliyal.common.utils.getKeyPassPasswordLength
import com.yogeshpaliyal.common.utils.isBiometricEnable
import com.yogeshpaliyal.common.utils.setBiometricEnable
import com.yogeshpaliyal.keypass.R
import com.yogeshpaliyal.keypass.ui.generate.ui.components.DEFAULT_PASSWORD_LENGTH
import com.yogeshpaliyal.keypass.ui.home.DashboardViewModel
import com.yogeshpaliyal.keypass.ui.redux.actions.Action
import com.yogeshpaliyal.keypass.ui.redux.actions.IntentNavigation
@@ -58,6 +62,7 @@ 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 com.yogeshpaliyal.keypass.ui.redux.states.ChangeDefaultPasswordLengthState
import kotlinx.coroutines.launch
import org.reduxkotlin.compose.rememberTypedDispatcher
@@ -153,6 +158,12 @@ fun MySettingCompose() {
)
}
// Retrieving saved password length
var savedPasswordLength by remember { mutableStateOf(DEFAULT_PASSWORD_LENGTH) }
LaunchedEffect(key1 = Unit) {
context.getKeyPassPasswordLength()?.let { value -> savedPasswordLength = value }
}
Column {
PreferenceItem(title = R.string.security, isCategory = true)
PreferenceItem(
@@ -174,6 +185,13 @@ fun MySettingCompose() {
) {
dispatchAction(NavigationAction(ChangeAppPasswordState()))
}
val changePasswordLengthSummary = context.getString(R.string.default_password_length)
PreferenceItem(
title = R.string.change_password_length,
summaryStr = "$changePasswordLengthSummary: ${savedPasswordLength.toInt()}"
) {
dispatchAction(NavigationAction(ChangeDefaultPasswordLengthState()))
}
BiometricsOption()

View File

@@ -95,4 +95,6 @@
<string name="backup_folder">مجلد النسخ الاحتياطي</string>
<string name="backup">دعم</string>
<string name="turn_on_backup">قم بتشغيل النسخ الاحتياطية</string>
<string name="change_password_length">تغيير طول كلمة المرور</string>
<string name="default_password_length">الطول الافتراضي لكلمة المرور</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">ফোন সেটিংস থেকে প্রথমে আপনার ডিভাইসের জন্য পাসওয়ার্ড সেট করুন</string>
<string name="authentication_failed">প্রমাণীকরণ ব্যর্থ হয়েছে</string>
<string name="authentication_error">প্রমাণীকরণ ত্রুটি %s</string>
<string name="change_password_length">পাসওয়ার্ডের দৈর্ঘ্য পরিবর্তন করুন</string>
<string name="default_password_length">ডিফল্ট পাসওয়ার্ড দৈর্ঘ্য</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="enter_password">Passwort eingeben</string>
<string name="str_continue">Weitermachen</string>
<string name="descending">Absteigend</string>
<string name="change_password_length">Passwortlänge ändern</string>
<string name="default_password_length">Standardlänge des Passworts</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="old_password">Contraseña antigua</string>
<string name="blank_old_password">Por favor, introduzca su contraseña anterior</string>
<string name="unlock_with_biometric">Desbloqueo con biométrico</string>
<string name="change_password_length">Cambiar la longitud de la contraseña</string>
<string name="default_password_length">Longitud de contraseña predeterminada</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="authentication_failed">Authentification échouée</string>
<string name="authentication_error">Erreur d\'authentification %s</string>
<string name="delete_account_title">Es-tu sûr\?</string>
<string name="change_password_length">Modifier la longueur du mot de passe</string>
<string name="default_password_length">Longueur du mot de passe par défaut</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">કૃપા કરીને ફોન સેટિંગ્સમાંથી પહેલા તમારા ઉપકરણ માટે પાસવર્ડ સેટ કરો</string>
<string name="authentication_failed">પ્રમાણીકરણ નિષ્ફળ થયું</string>
<string name="authentication_error">પ્રમાણીકરણ ભૂલ %s</string>
<string name="change_password_length">પાસવર્ડ લંબાઈ બદલો</string>
<string name="default_password_length">ડિફૉલ્ટ પાસવર્ડ લંબાઈ</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">કૃપા કરીને ફોન સેટિંગ્સમાંથી પહેલા તમારા ઉપકરણ માટે પાસવર્ડ સેટ કરો</string>
<string name="authentication_failed">પ્રમાણીકરણ નિષ્ફળ થયું</string>
<string name="authentication_error">પ્રમાણીકરણ ભૂલ %s</string>
<string name="change_password_length">પાસવર્ડ લંબાઈ બદલો</string>
<string name="default_password_length">ડિફૉલ્ટ પાસવર્ડ લંબાઈ</string>
</resources>

View File

@@ -96,4 +96,6 @@
<string name="blank_confirm_password">कृपया पुष्टि पासवर्ड दर्ज करें</string>
<string name="password_change_success">पासवर्ड सफलतापूर्वक बदला गया</string>
<string name="authentication_error">प्रमाणीकरण त्रुटि %s</string>
<string name="change_password_length">पासवर्ड की लंबाई बदलें</string>
<string name="default_password_length">डिफ़ॉल्ट पासवर्ड लंबाई</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">Si prega di impostare la password per il dispositivo prima dalle impostazioni del telefono</string>
<string name="authentication_failed">Autenticazione non riuscita</string>
<string name="authentication_error">Errore di autenticazione %s</string>
<string name="change_password_length">Modifica la lunghezza della password</string>
<string name="default_password_length">Lunghezza password predefinita</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_length">パスワードの長さ</string>
<string name="password">パスワード</string>
<string name="uppercase_alphabets">大文字のアルファベット</string>
<string name="change_password_length">パスワードの長さを変更する</string>
<string name="default_password_length">デフォルトのパスワードの長さ</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">कृपया फोन सेटिंग्जमधून प्रथम तुमच्या डिव्हाइससाठी पासवर्ड सेट करा</string>
<string name="authentication_failed">प्रमाणीकरण अयशस्वी</string>
<string name="authentication_error">प्रमाणीकरण त्रुटी %s</string>
<string name="change_password_length">पासवर्डची लांबी बदला</string>
<string name="default_password_length">डीफॉल्ट पासवर्ड लांबी</string>
</resources>

View File

@@ -96,4 +96,6 @@
<string name="blank_confirm_password">Por favor, digite a senha de confirmação</string>
<string name="password_change_success">Senha alterada com sucesso</string>
<string name="authentication_error">Erro de autenticação %s</string>
<string name="change_password_length">Alterar tamanho da senha</string>
<string name="default_password_length">Comprimento da senha padrão</string>
</resources>

View File

@@ -96,4 +96,6 @@
<string name="password_set_from_settings">Пожалуйста, сначала установите пароль для вашего устройства в настройках телефона</string>
<string name="authentication_failed">Ошибка проверки подлинности</string>
<string name="authentication_error">Ошибка аутентификации %s</string>
<string name="change_password_length">Изменить длину пароля</string>
<string name="default_password_length">Длина пароля по умолчанию</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_change_success">கடவுச்சொல் வெற்றிகரமாக மாற்றப்பட்டது</string>
<string name="biometric_error_no_hardware">இந்தச் சாதனத்தில் பயோமெட்ரிக் அம்சங்கள் எதுவும் இல்லை.</string>
<string name="biometric_error_hw_unavailable">பயோமெட்ரிக் அம்சங்கள் தற்போது கிடைக்கவில்லை.</string>
<string name="change_password_length">கடவுச்சொல் நீளத்தை மாற்றவும்</string>
<string name="default_password_length">இயல்புநிலை கடவுச்சொல் நீளம்</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">దయచేసి ముందుగా ఫోన్ సెట్టింగ్‌ల నుండి మీ పరికరానికి పాస్‌వర్డ్‌ని సెట్ చేయండి</string>
<string name="authentication_failed">ప్రామాణీకరణ విఫలమైంది</string>
<string name="authentication_error">ప్రమాణీకరణ లోపం %s</string>
<string name="change_password_length">పాస్వర్డ్ పొడవు మార్చండి</string>
<string name="default_password_length">డిఫాల్ట్ పాస్‌వర్డ్ పొడవు</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">براہ کرم فون کی ترتیبات سے پہلے اپنے آلے کے لیے پاس ورڈ سیٹ کریں</string>
<string name="authentication_failed">تصدیق میں ناکام رہے</string>
<string name="authentication_error">تصدیق کی خرابی %s</string>
<string name="change_password_length">پاس ورڈ کی لمبائی تبدیل کریں۔</string>
<string name="default_password_length">پہلے سے طے شدہ پاس ورڈ کی لمبائی</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="password_set_from_settings">براہ کرم فون کی ترتیبات سے پہلے اپنے آلے کے لیے پاس ورڈ سیٹ کریں</string>
<string name="authentication_failed">تصدیق میں ناکام رہے</string>
<string name="authentication_error">تصدیق کی خرابی %s</string>
<string name="change_password_length">پاس ورڈ کی لمبائی تبدیل کریں۔</string>
<string name="default_password_length">پہلے سے طے شدہ پاس ورڈ کی لمبائی</string>
</resources>

View File

@@ -95,4 +95,6 @@
<string name="biometric_error_hw_unavailable">بائیو میٹرک فیچرز فی الحال دستیاب نہیں ہیں۔</string>
<string name="biometric_error_none_enrolled">اپنے آلے پر بائیو میٹرک سیٹ اپ کریں۔</string>
<string name="unlock_with_biometric">بائیو میٹرک کے ساتھ انلاک کریں</string>
<string name="change_password_length">پاس ورڈ کی لمبائی تبدیل کریں۔</string>
<string name="default_password_length">پہلے سے طے شدہ پاس ورڈ کی لمبائی</string>
</resources>

View File

@@ -96,4 +96,6 @@
<string name="blank_confirm_password">请输入确认密码</string>
<string name="password_change_success">密码修改成功</string>
<string name="authentication_error">身份验证错误 %s</string>
<string name="change_password_length">更改密码长度</string>
<string name="default_password_length">默认密码长度</string>
</resources>

View File

@@ -105,5 +105,7 @@
<string name="password_set_from_settings">Please set password for your device first from phone settings</string>
<string name="authentication_failed">Authentication Failed</string>
<string name="authentication_error">Authentication Error %s</string>
<string name="change_password_length">Change password length</string>
<string name="default_password_length">Default password length</string>
</resources>