mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Compare commits
55 Commits
5bdc72aa67
...
feature/Us
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c88413f7f7 | ||
|
|
7b1fb8a4bf | ||
|
|
3567fa797b | ||
|
|
eb41233e57 | ||
|
|
b394a99e40 | ||
|
|
2bbb40e513 | ||
|
|
09ef69e6ae | ||
|
|
762ac8f77b | ||
|
|
d28087d8d8 | ||
|
|
17d4c363ac | ||
|
|
c754b6a049 | ||
|
|
9c6241afc9 | ||
|
|
f6774b6d51 | ||
|
|
108a61905e | ||
|
|
d251788b1a | ||
|
|
7ed8a44168 | ||
|
|
844b1dfc79 | ||
|
|
d087fcc930 | ||
|
|
5fd25c6150 | ||
|
|
c1cfddddbe | ||
|
|
9146315001 | ||
|
|
609b536898 | ||
|
|
f9051ce787 | ||
|
|
d90d175bd8 | ||
|
|
c17fba8ef7 | ||
|
|
ed095ad0a7 | ||
|
|
82a8776911 | ||
|
|
753e9c4721 | ||
|
|
b64094ed20 | ||
|
|
bc854c63f7 | ||
|
|
3b793a72b8 | ||
|
|
f19afbdb2e | ||
|
|
622e9cefdd | ||
|
|
3ba56677ba | ||
|
|
39b4b4df70 | ||
|
|
4180ca92b0 | ||
|
|
bc9d00a1e1 | ||
|
|
612db4a6fc | ||
|
|
e74176f3bc | ||
|
|
af1fba42a0 | ||
|
|
bebf30aec1 | ||
|
|
321bb46df5 | ||
|
|
429f6db93f | ||
|
|
fc5a13160a | ||
|
|
c6eee8d449 | ||
|
|
7d227f372f | ||
|
|
3ac56b974f | ||
|
|
2e85ea401b | ||
|
|
fd080fb952 | ||
|
|
cc8e07366a | ||
|
|
c21bcbdbc2 | ||
|
|
e2ee17dae7 | ||
|
|
e68830fa25 | ||
|
|
2e237fba2d | ||
|
|
e68863a154 |
@@ -1,3 +1,9 @@
|
||||
KeePassDX(4.3.0)
|
||||
* Manual change of app language #1884 #1990
|
||||
* Add Passkey User Verification #2283
|
||||
* Fix autofill username detection #2276
|
||||
* Fix Passkey in passwordless mode #2282
|
||||
|
||||
KeePassDX(4.2.4)
|
||||
* Fix remembering database location #2262
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ android {
|
||||
applicationId "com.kunzisoft.keepass"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 35
|
||||
versionCode = 149
|
||||
versionName = "4.2.4"
|
||||
versionCode = 150
|
||||
versionName = "4.3.0"
|
||||
multiDexEnabled true
|
||||
|
||||
testApplicationId = "com.kunzisoft.keepass.tests"
|
||||
@@ -110,6 +110,10 @@ android {
|
||||
// Bouncy castle bug https://github.com/bcgit/bc-java/issues/1685
|
||||
resources.pickFirsts.add('META-INF/versions/9/OSGI-INF/MANIFEST.MF')
|
||||
}
|
||||
|
||||
androidResources {
|
||||
generateLocaleConfig true
|
||||
}
|
||||
}
|
||||
|
||||
def room_version = "2.5.1"
|
||||
|
||||
@@ -41,6 +41,9 @@ import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
@@ -53,6 +56,11 @@ import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseLockActivity
|
||||
import com.kunzisoft.keepass.adapters.TagsAdapter
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.isUserVerificationNeeded
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.requestShowUnprotectField
|
||||
import com.kunzisoft.keepass.credentialprovider.magikeyboard.MagikeyboardService
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
@@ -78,7 +86,10 @@ import com.kunzisoft.keepass.view.changeTitleColor
|
||||
import com.kunzisoft.keepass.view.hideByFading
|
||||
import com.kunzisoft.keepass.view.setTransparentNavigationBar
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
import com.kunzisoft.keepass.view.showError
|
||||
import com.kunzisoft.keepass.viewmodels.EntryViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.EnumSet
|
||||
import java.util.UUID
|
||||
|
||||
@@ -100,14 +111,10 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
private var loadingView: ProgressBar? = null
|
||||
|
||||
private val mEntryViewModel: EntryViewModel by viewModels()
|
||||
private val mUserVerificationViewModel: UserVerificationViewModel by viewModels()
|
||||
|
||||
private val mEntryActivityEducation = EntryActivityEducation(this)
|
||||
|
||||
private var mMainEntryId: NodeId<UUID>? = null
|
||||
private var mHistoryPosition: Int = -1
|
||||
private var mEntryIsHistory: Boolean = false
|
||||
private var mEntryLoaded = false
|
||||
|
||||
private var mAttachmentFileBinderManager: AttachmentFileBinderManager? = null
|
||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||
private var mAttachmentSelected: Attachment? = null
|
||||
@@ -210,7 +217,7 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
|
||||
mEntryViewModel.loadEntry(mDatabase, mainEntryId, historyPosition)
|
||||
}
|
||||
} catch (e: ClassCastException) {
|
||||
} catch (_: ClassCastException) {
|
||||
Log.e(TAG, "Unable to retrieve the entry key")
|
||||
}
|
||||
|
||||
@@ -238,13 +245,9 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
|
||||
mEntryViewModel.entryInfoHistory.observe(this) { entryInfoHistory ->
|
||||
if (entryInfoHistory != null) {
|
||||
this.mMainEntryId = entryInfoHistory.mainEntryId
|
||||
|
||||
// Manage history position
|
||||
val historyPosition = entryInfoHistory.historyPosition
|
||||
this.mHistoryPosition = historyPosition
|
||||
val entryIsHistory = historyPosition > -1
|
||||
this.mEntryIsHistory = entryIsHistory
|
||||
// Assign history dedicated view
|
||||
historyView?.visibility = if (entryIsHistory) View.VISIBLE else View.GONE
|
||||
// TODO History badge
|
||||
@@ -279,7 +282,6 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
mForegroundColor = if (showEntryColors) entryInfo.foregroundColor else null
|
||||
|
||||
loadingView?.hideByFading()
|
||||
mEntryLoaded = true
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
@@ -322,6 +324,73 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mEntryViewModel.entryState.collect { entryState ->
|
||||
when (entryState) {
|
||||
is EntryViewModel.EntryState.Loading -> {}
|
||||
is EntryViewModel.EntryState.RequestUnprotectField -> {
|
||||
mDatabase?.let { database ->
|
||||
requestShowUnprotectField(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
database = database,
|
||||
protectedFieldView = entryState.protectedFieldView
|
||||
)
|
||||
}
|
||||
mEntryViewModel.actionPerformed()
|
||||
}
|
||||
is EntryViewModel.EntryState.RequestCopyProtectedField -> {
|
||||
mDatabase?.let { database ->
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.COPY_PROTECTED_FIELD,
|
||||
database = database,
|
||||
field = entryState.field,
|
||||
)
|
||||
)
|
||||
}
|
||||
mEntryViewModel.actionPerformed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mUserVerificationViewModel.userVerificationState.collect { uVState ->
|
||||
when (uVState) {
|
||||
is UserVerificationViewModel.UVState.Loading -> {}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationCanceled -> {
|
||||
coordinatorLayout?.showError(uVState.error)
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationSucceeded -> {
|
||||
val data = uVState.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.SHOW_PROTECTED_FIELD -> {
|
||||
// Unprotect field by its view
|
||||
data.protectedFieldView?.unprotect()
|
||||
}
|
||||
UserVerificationActionType.COPY_PROTECTED_FIELD -> {
|
||||
// Copy field value
|
||||
data.field?.let {
|
||||
mEntryViewModel.copyToClipboard(it)
|
||||
}
|
||||
}
|
||||
UserVerificationActionType.EDIT_ENTRY -> {
|
||||
// Edit Entry
|
||||
editEntry(data.database, data.entryId)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun finishActivityIfReloadRequested(): Boolean {
|
||||
@@ -410,13 +479,13 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
if (mEntryLoaded) {
|
||||
if (mEntryViewModel.entryLoaded) {
|
||||
val inflater = menuInflater
|
||||
|
||||
inflater.inflate(R.menu.entry, menu)
|
||||
inflater.inflate(R.menu.database, menu)
|
||||
|
||||
if (mEntryIsHistory && !mDatabaseReadOnly) {
|
||||
if (mEntryViewModel.entryIsHistory && !mDatabaseReadOnly) {
|
||||
inflater.inflate(R.menu.entry_history, menu)
|
||||
}
|
||||
|
||||
@@ -429,7 +498,7 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
||||
if (mEntryIsHistory || mDatabaseReadOnly) {
|
||||
if (mEntryViewModel.entryIsHistory || mDatabaseReadOnly) {
|
||||
menu?.findItem(R.id.menu_save_database)?.isVisible = false
|
||||
menu?.findItem(R.id.menu_merge_database)?.isVisible = false
|
||||
menu?.findItem(R.id.menu_edit)?.isVisible = false
|
||||
@@ -474,34 +543,53 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun editEntry(database: ContextualDatabase?, entryId: NodeId<*>?) {
|
||||
database?.let { database ->
|
||||
entryId?.let { entryId ->
|
||||
EntryEditActivity.launch(
|
||||
activity = this@EntryActivity,
|
||||
database = database,
|
||||
registrationType = EntryEditActivity.RegistrationType.UPDATE,
|
||||
nodeId = entryId,
|
||||
activityResultLauncher = mEntryActivityResultLauncher
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.menu_edit -> {
|
||||
mDatabase?.let { database ->
|
||||
mMainEntryId?.let { entryId ->
|
||||
EntryEditActivity.launch(
|
||||
activity = this,
|
||||
database = database,
|
||||
registrationType = EntryEditActivity.RegistrationType.UPDATE,
|
||||
nodeId = entryId,
|
||||
activityResultLauncher = mEntryActivityResultLauncher
|
||||
if (mEntryViewModel.entryInfo?.isUserVerificationNeeded() == true) {
|
||||
mDatabase?.let { database ->
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_ENTRY,
|
||||
database = database,
|
||||
entryId = mEntryViewModel.mainEntryId
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
editEntry(mDatabase, mEntryViewModel.mainEntryId)
|
||||
}
|
||||
return true
|
||||
}
|
||||
R.id.menu_restore_entry_history -> {
|
||||
mMainEntryId?.let { mainEntryId ->
|
||||
mEntryViewModel.mainEntryId?.let { mainEntryId ->
|
||||
restoreEntryHistory(
|
||||
mainEntryId,
|
||||
mHistoryPosition)
|
||||
mEntryViewModel.historyPosition
|
||||
)
|
||||
}
|
||||
}
|
||||
R.id.menu_delete_entry_history -> {
|
||||
mMainEntryId?.let { mainEntryId ->
|
||||
mEntryViewModel.mainEntryId?.let { mainEntryId ->
|
||||
deleteEntryHistory(
|
||||
mainEntryId,
|
||||
mHistoryPosition)
|
||||
mEntryViewModel.historyPosition
|
||||
)
|
||||
}
|
||||
}
|
||||
R.id.menu_save_database -> {
|
||||
@@ -521,7 +609,7 @@ class EntryActivity : DatabaseLockActivity() {
|
||||
override fun finish() {
|
||||
// Transit data in previous Activity after an update
|
||||
Intent().apply {
|
||||
putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mMainEntryId)
|
||||
putExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY, mEntryViewModel.mainEntryId)
|
||||
setResult(RESULT_OK, this)
|
||||
}
|
||||
super.finish()
|
||||
|
||||
@@ -63,6 +63,8 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.buildSpecia
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.retrieveRegisterInfo
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.retrieveSearchInfo
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.requestShowUnprotectField
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.buildPasskeyResponseAndSetResult
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
@@ -98,9 +100,11 @@ import com.kunzisoft.keepass.view.asError
|
||||
import com.kunzisoft.keepass.view.hideByFading
|
||||
import com.kunzisoft.keepass.view.setTransparentNavigationBar
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
import com.kunzisoft.keepass.view.showError
|
||||
import com.kunzisoft.keepass.view.updateLockPaddingStart
|
||||
import com.kunzisoft.keepass.viewmodels.ColorPickerViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.EntryEditViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.EnumSet
|
||||
import java.util.UUID
|
||||
@@ -129,6 +133,7 @@ class EntryEditActivity : DatabaseLockActivity(),
|
||||
private var mTemplatesSelectorAdapter: TemplatesSelectorAdapter? = null
|
||||
|
||||
private val mColorPickerViewModel: ColorPickerViewModel by viewModels()
|
||||
private val mUserVerificationViewModel: UserVerificationViewModel by viewModels()
|
||||
|
||||
private var mAllowCustomFields = false
|
||||
private var mAllowOTP = false
|
||||
@@ -383,23 +388,52 @@ class EntryEditActivity : DatabaseLockActivity(),
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mEntryEditViewModel.uiState.collect { uiState ->
|
||||
mEntryEditViewModel.entryEditState.collect { uiState ->
|
||||
when (uiState) {
|
||||
EntryEditViewModel.UIState.Loading -> {}
|
||||
EntryEditViewModel.UIState.ShowOverwriteMessage -> {
|
||||
if (mEntryEditViewModel.warningOverwriteDataAlreadyApproved.not()) {
|
||||
AlertDialog.Builder(this@EntryEditActivity)
|
||||
.setTitle(R.string.warning_overwrite_data_title)
|
||||
.setMessage(R.string.warning_overwrite_data_description)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
mEntryEditViewModel.backPressedAlreadyApproved = true
|
||||
onCancelSpecialMode()
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
mEntryEditViewModel.warningOverwriteDataAlreadyApproved = true
|
||||
}
|
||||
.create().show()
|
||||
is EntryEditViewModel.EntryEditState.Loading -> {}
|
||||
is EntryEditViewModel.EntryEditState.ShowOverwriteMessage -> {
|
||||
AlertDialog.Builder(this@EntryEditActivity)
|
||||
.setTitle(R.string.warning_overwrite_data_title)
|
||||
.setMessage(R.string.warning_overwrite_data_description)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
mEntryEditViewModel.backPressedAlreadyApproved = true
|
||||
onCancelSpecialMode()
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok) { _, _ -> }
|
||||
.create().show()
|
||||
mEntryEditViewModel.actionPerformed()
|
||||
}
|
||||
is EntryEditViewModel.EntryEditState.RequestUnprotectField -> {
|
||||
mDatabase?.let { database ->
|
||||
requestShowUnprotectField(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
database = database,
|
||||
protectedFieldView = uiState.protectedFieldView
|
||||
)
|
||||
}
|
||||
mEntryEditViewModel.actionPerformed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mUserVerificationViewModel.userVerificationState.collect { uVState ->
|
||||
when (uVState) {
|
||||
is UserVerificationViewModel.UVState.Loading -> {}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationCanceled -> {
|
||||
coordinatorLayout?.showError(uVState.error)
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationSucceeded -> {
|
||||
when (uVState.dataToVerify.actionType) {
|
||||
UserVerificationActionType.SHOW_PROTECTED_FIELD -> {
|
||||
uVState.dataToVerify.protectedFieldView?.unprotect()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,7 +482,7 @@ class EntryEditActivity : DatabaseLockActivity(),
|
||||
searchAction = {
|
||||
// Nothing when search retrieved
|
||||
},
|
||||
selectionAction = { intentSender, typeMode, searchInfo ->
|
||||
selectionAction = { _, typeMode, _ ->
|
||||
when(typeMode) {
|
||||
TypeMode.DEFAULT -> {}
|
||||
TypeMode.MAGIKEYBOARD ->
|
||||
|
||||
@@ -52,6 +52,9 @@ import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
@@ -72,10 +75,13 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.removeModes
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.retrieveSearchInfo
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.isUserVerificationNeeded
|
||||
import com.kunzisoft.keepass.credentialprovider.magikeyboard.MagikeyboardService
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.buildPasskeyResponseAndSetResult
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.MainCredential
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
import com.kunzisoft.keepass.database.element.Entry
|
||||
import com.kunzisoft.keepass.database.element.Group
|
||||
@@ -117,10 +123,14 @@ import com.kunzisoft.keepass.view.applyWindowInsets
|
||||
import com.kunzisoft.keepass.view.hideByFading
|
||||
import com.kunzisoft.keepass.view.setTransparentNavigationBar
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
import com.kunzisoft.keepass.view.showError
|
||||
import com.kunzisoft.keepass.view.toastError
|
||||
import com.kunzisoft.keepass.view.updateLockPaddingStart
|
||||
import com.kunzisoft.keepass.viewmodels.GroupEditViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.GroupViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.MainCredentialViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.LocalDateTime
|
||||
import java.util.EnumSet
|
||||
|
||||
@@ -130,8 +140,7 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
GroupFragment.NodesActionMenuListener,
|
||||
GroupFragment.OnScrollListener,
|
||||
GroupFragment.GroupRefreshedListener,
|
||||
SortDialogFragment.SortSelectionListener,
|
||||
MainCredentialDialogFragment.AskMainCredentialDialogListener {
|
||||
SortDialogFragment.SortSelectionListener {
|
||||
|
||||
// Views
|
||||
private var header: ViewGroup? = null
|
||||
@@ -156,6 +165,8 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
|
||||
private val mGroupViewModel: GroupViewModel by viewModels()
|
||||
private val mGroupEditViewModel: GroupEditViewModel by viewModels()
|
||||
private val mMainCredentialViewModel: MainCredentialViewModel by viewModels()
|
||||
private val mUserVerificationViewModel: UserVerificationViewModel by viewModels()
|
||||
|
||||
private val mGroupActivityEducation = GroupActivityEducation(this)
|
||||
|
||||
@@ -356,14 +367,22 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
SettingsActivity.launch(this@GroupActivity, true)
|
||||
}
|
||||
R.id.menu_merge_from -> {
|
||||
mExternalFileHelper?.openDocument()
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.MERGE_FROM_DATABASE,
|
||||
database = mDatabase
|
||||
)
|
||||
)
|
||||
}
|
||||
R.id.menu_save_copy_to -> {
|
||||
mExternalFileHelper?.createDocument(
|
||||
getString(R.string.database_file_name_default) +
|
||||
"_" +
|
||||
LocalDateTime.now().toString() +
|
||||
mDatabase?.defaultFileExtension)
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.SAVE_DATABASE_COPY_TO,
|
||||
database = mDatabase
|
||||
)
|
||||
)
|
||||
}
|
||||
R.id.menu_lock_all -> {
|
||||
lockAndExit()
|
||||
@@ -548,6 +567,58 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mMainCredentialViewModel.uiState.collect { credentialState ->
|
||||
when (credentialState) {
|
||||
is MainCredentialViewModel.UIState.Loading -> {}
|
||||
is MainCredentialViewModel.UIState.OnMainCredentialEntered -> {
|
||||
mergeDatabaseFrom(credentialState.databaseUri, credentialState.mainCredential)
|
||||
mMainCredentialViewModel.onActionReceived()
|
||||
}
|
||||
is MainCredentialViewModel.UIState.OnMainCredentialCanceled -> {
|
||||
mMainCredentialViewModel.onActionReceived()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mUserVerificationViewModel.userVerificationState.collect { uVState ->
|
||||
when (uVState) {
|
||||
is UserVerificationViewModel.UVState.Loading -> {}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationCanceled -> {
|
||||
coordinatorLayout?.showError(uVState.error)
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationSucceeded -> {
|
||||
val data = uVState.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.EDIT_ENTRY -> {
|
||||
editEntry(uVState.dataToVerify.database, uVState.dataToVerify.entryId)
|
||||
}
|
||||
UserVerificationActionType.MERGE_FROM_DATABASE -> {
|
||||
mExternalFileHelper?.openDocument()
|
||||
}
|
||||
UserVerificationActionType.SAVE_DATABASE_COPY_TO -> {
|
||||
mExternalFileHelper?.createDocument(
|
||||
getString(R.string.database_file_name_default) +
|
||||
"_" +
|
||||
LocalDateTime.now().toString() +
|
||||
uVState.dataToVerify.database?.defaultFileExtension
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun viewToInvalidateTimeout(): View? {
|
||||
@@ -668,14 +739,6 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
result: ActionRunnable.Result
|
||||
) {
|
||||
super.onDatabaseActionFinished(database, actionTask, result)
|
||||
|
||||
var entry: Entry? = null
|
||||
try {
|
||||
entry = result.data?.getNewEntry(database)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to retrieve entry action for selection", e)
|
||||
}
|
||||
|
||||
when (actionTask) {
|
||||
ACTION_DATABASE_UPDATE_ENTRY_TASK -> {
|
||||
if (result.isSuccess) {
|
||||
@@ -687,7 +750,13 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
searchAction = {
|
||||
// Search not used
|
||||
},
|
||||
selectionAction = { intentSenderMode, typeMode, searchInfo ->
|
||||
selectionAction = { _, typeMode, _ ->
|
||||
var entry: Entry? = null
|
||||
try {
|
||||
entry = result.data?.getNewEntry(database)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to retrieve entry action for selection", e)
|
||||
}
|
||||
when (typeMode) {
|
||||
TypeMode.DEFAULT -> {}
|
||||
TypeMode.MAGIKEYBOARD -> entry?.let {
|
||||
@@ -701,19 +770,17 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
}
|
||||
}
|
||||
},
|
||||
registrationAction = { intentSenderMode, typeMode, searchInfo ->
|
||||
registrationAction = { _, _, _ ->
|
||||
// Save not used
|
||||
}
|
||||
)
|
||||
}
|
||||
coordinatorError?.showActionErrorIfNeeded(result)
|
||||
// Reload the group
|
||||
loadGroup()
|
||||
finishNodeAction()
|
||||
}
|
||||
}
|
||||
|
||||
coordinatorError?.showActionErrorIfNeeded(result)
|
||||
|
||||
// Reload the group
|
||||
loadGroup()
|
||||
finishNodeAction()
|
||||
}
|
||||
|
||||
private fun manageIntent(intent: Intent?) {
|
||||
@@ -860,7 +927,7 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
searchAction = {
|
||||
// Nothing here, a search is simply performed
|
||||
},
|
||||
selectionAction = { intentSenderMode, typeMode, searchInfo ->
|
||||
selectionAction = { _, typeMode, searchInfo ->
|
||||
when (typeMode) {
|
||||
TypeMode.DEFAULT -> {}
|
||||
TypeMode.MAGIKEYBOARD -> {
|
||||
@@ -994,6 +1061,20 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
).containsSearchInfo(searchInfo)
|
||||
}
|
||||
|
||||
private fun editEntry(database: ContextualDatabase?, entryId: NodeId<*>?) {
|
||||
database?.let {
|
||||
entryId?.let {
|
||||
EntryEditActivity.launch(
|
||||
activity = this@GroupActivity,
|
||||
database = database,
|
||||
registrationType = EntryEditActivity.RegistrationType.UPDATE,
|
||||
nodeId = entryId,
|
||||
activityResultLauncher = mEntryActivityResultLauncher
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishNodeAction() {
|
||||
actionNodeMode?.finish()
|
||||
}
|
||||
@@ -1043,13 +1124,18 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
launchDialogForGroupUpdate(node as Group)
|
||||
}
|
||||
Type.ENTRY -> {
|
||||
EntryEditActivity.launch(
|
||||
activity = this@GroupActivity,
|
||||
database = database,
|
||||
registrationType = EntryEditActivity.RegistrationType.UPDATE,
|
||||
nodeId = (node as Entry).nodeId,
|
||||
activityResultLauncher = mEntryActivityResultLauncher
|
||||
)
|
||||
if ((node as Entry).getEntryInfo(database).isUserVerificationNeeded()) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = mUserVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_ENTRY,
|
||||
database = database,
|
||||
entryId = node.nodeId
|
||||
)
|
||||
)
|
||||
} else {
|
||||
editEntry(database, node.nodeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -1133,20 +1219,6 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onAskMainCredentialDialogPositiveClick(
|
||||
databaseUri: Uri?,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
databaseUri?.let {
|
||||
mergeDatabaseFrom(it, mainCredential)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAskMainCredentialDialogNegativeClick(
|
||||
databaseUri: Uri?,
|
||||
mainCredential: MainCredential
|
||||
) { }
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
@@ -1644,13 +1716,13 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
context = activity,
|
||||
database = database,
|
||||
searchInfo = searchInfo,
|
||||
onItemsFound = { openedDatabase, items ->
|
||||
onItemsFound = { _, items ->
|
||||
when (typeMode) {
|
||||
TypeMode.DEFAULT -> {}
|
||||
TypeMode.MAGIKEYBOARD -> {
|
||||
MagikeyboardService.performSelection(
|
||||
items = items,
|
||||
actionPopulateKeyboard = { entryInfo ->
|
||||
actionPopulateKeyboard = { _ ->
|
||||
activity.buildSpecialModeResponseAndSetResult(items)
|
||||
onValidateSpecialMode()
|
||||
},
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2025 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePassDX.
|
||||
*
|
||||
* KeePassDX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.text.InputFilter
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.database.element.MasterCredential
|
||||
import com.kunzisoft.keepass.utils.UriUtil.openUrl
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
|
||||
|
||||
class CheckDatabaseCredentialDialogFragment : DatabaseDialogFragment() {
|
||||
|
||||
private val userVerificationViewModel: UserVerificationViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val inflater = activity.layoutInflater
|
||||
val rootView = inflater.inflate(R.layout.fragment_check_database_credential, null)
|
||||
val editText = rootView.findViewById<TextView>(R.id.setup_check_password_edit_text)
|
||||
editText.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(
|
||||
MasterCredential.CHECK_KEY_PASSWORD_LENGTH)
|
||||
)
|
||||
builder.setView(rootView)
|
||||
.setPositiveButton(R.string.check) { _, _ ->
|
||||
userVerificationViewModel.checkMainCredential(
|
||||
editText.text.toString()
|
||||
)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
userVerificationViewModel.onUserVerificationFailed()
|
||||
dismiss()
|
||||
}
|
||||
rootView.findViewById<View>(R.id.user_verification_information)?.setOnClickListener {
|
||||
activity.openUrl(R.string.user_verification_explanation_url)
|
||||
}
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
return super.onCreateDialog(savedInstanceState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun getInstance(): CheckDatabaseCredentialDialogFragment {
|
||||
val fragment = CheckDatabaseCredentialDialogFragment()
|
||||
val args = Bundle()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,45 +20,27 @@
|
||||
package com.kunzisoft.keepass.activities.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
|
||||
import com.kunzisoft.keepass.database.MainCredential
|
||||
import com.kunzisoft.keepass.database.exception.FileNotFoundDatabaseException
|
||||
import com.kunzisoft.keepass.utils.UriUtil.getDocumentFile
|
||||
import com.kunzisoft.keepass.utils.getParcelableCompat
|
||||
import com.kunzisoft.keepass.view.MainCredentialView
|
||||
import com.kunzisoft.keepass.viewmodels.MainCredentialViewModel
|
||||
|
||||
class MainCredentialDialogFragment : DatabaseDialogFragment() {
|
||||
|
||||
private var mainCredentialView: MainCredentialView? = null
|
||||
|
||||
private var mListener: AskMainCredentialDialogListener? = null
|
||||
|
||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||
|
||||
interface AskMainCredentialDialogListener {
|
||||
fun onAskMainCredentialDialogPositiveClick(databaseUri: Uri?, mainCredential: MainCredential)
|
||||
fun onAskMainCredentialDialogNegativeClick(databaseUri: Uri?, mainCredential: MainCredential)
|
||||
}
|
||||
|
||||
override fun onAttach(activity: Context) {
|
||||
super.onAttach(activity)
|
||||
try {
|
||||
mListener = activity as AskMainCredentialDialogListener
|
||||
} catch (e: ClassCastException) {
|
||||
throw ClassCastException(activity.toString()
|
||||
+ " must implement " + AskMainCredentialDialogListener::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
mListener = null
|
||||
super.onDetach()
|
||||
}
|
||||
private val mMainCredentialViewModel: MainCredentialViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
activity?.let { activity ->
|
||||
@@ -76,30 +58,35 @@ class MainCredentialDialogFragment : DatabaseDialogFragment() {
|
||||
databaseUri?.let {
|
||||
root.findViewById<TextView>(R.id.title_database)?.text =
|
||||
it.getDocumentFile(requireContext())?.name
|
||||
}
|
||||
builder.setView(root)
|
||||
|
||||
builder.setView(root)
|
||||
// Add action buttons
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
mListener?.onAskMainCredentialDialogPositiveClick(
|
||||
databaseUri,
|
||||
retrieveMainCredential()
|
||||
mMainCredentialViewModel.validateMainCredential(
|
||||
databaseUri = databaseUri,
|
||||
mainCredential = retrieveMainCredential()
|
||||
)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||
mListener?.onAskMainCredentialDialogNegativeClick(
|
||||
databaseUri,
|
||||
retrieveMainCredential()
|
||||
mMainCredentialViewModel.cancelMainCredential(
|
||||
databaseUri = databaseUri
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
mExternalFileHelper = ExternalFileHelper(this)
|
||||
mExternalFileHelper?.buildOpenDocument { uri ->
|
||||
if (uri != null) {
|
||||
mainCredentialView?.populateKeyFileView(uri)
|
||||
mExternalFileHelper = ExternalFileHelper(this)
|
||||
mExternalFileHelper?.buildOpenDocument { uri ->
|
||||
if (uri != null) {
|
||||
mainCredentialView?.populateKeyFileView(uri)
|
||||
}
|
||||
}
|
||||
mainCredentialView?.setOpenKeyfileClickListener(mExternalFileHelper)
|
||||
} ?: run {
|
||||
mMainCredentialViewModel.cancelMainCredential(
|
||||
databaseUri = null,
|
||||
error = FileNotFoundDatabaseException()
|
||||
)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mainCredentialView?.setOpenKeyfileClickListener(mExternalFileHelper)
|
||||
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
@@ -116,6 +116,9 @@ class EntryEditFragment: DatabaseFragment() {
|
||||
setOnForegroundColorClickListener {
|
||||
mEntryEditViewModel.requestForegroundColorSelection(templateView.getForegroundColor())
|
||||
}
|
||||
setOnUnprotectClickListener { _, textEditFieldView ->
|
||||
mEntryEditViewModel.requestUnprotectField(textEditFieldView)
|
||||
}
|
||||
setOnCustomEditionActionClickListener { field ->
|
||||
mEntryEditViewModel.requestCustomFieldEdition(field)
|
||||
}
|
||||
|
||||
@@ -16,13 +16,10 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.adapters.EntryAttachmentsItemsAdapter
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||
import com.kunzisoft.keepass.database.helper.getLocalizedName
|
||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.StreamDirection
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||
import com.kunzisoft.keepass.utils.TimeUtil.getDateTimeString
|
||||
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||
import com.kunzisoft.keepass.view.TemplateView
|
||||
@@ -50,8 +47,6 @@ class EntryFragment: DatabaseFragment() {
|
||||
private lateinit var uuidContainerView: View
|
||||
private lateinit var uuidReferenceView: TextView
|
||||
|
||||
private var mClipboardHelper: ClipboardHelper? = null
|
||||
|
||||
private val mEntryViewModel: EntryViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater,
|
||||
@@ -66,10 +61,6 @@ class EntryFragment: DatabaseFragment() {
|
||||
savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
context?.let { context ->
|
||||
mClipboardHelper = ClipboardHelper(context)
|
||||
}
|
||||
|
||||
rootView = view
|
||||
// Hide only the first time
|
||||
if (savedInstanceState == null) {
|
||||
@@ -152,16 +143,14 @@ class EntryFragment: DatabaseFragment() {
|
||||
private fun assignEntryInfo(entryInfo: EntryInfo?) {
|
||||
// Set copy buttons
|
||||
templateView.apply {
|
||||
setOnUnprotectClickListener { protectedFieldView ->
|
||||
mEntryViewModel.requestUnprotectField(protectedFieldView)
|
||||
}
|
||||
setOnAskCopySafeClickListener {
|
||||
showClipboardDialog()
|
||||
}
|
||||
|
||||
setOnCopyActionClickListener { field ->
|
||||
mClipboardHelper?.timeoutCopyToClipboard(
|
||||
TemplateField.getLocalizedName(context, field.name),
|
||||
field.protectedValue.stringValue,
|
||||
field.protectedValue.isProtected
|
||||
)
|
||||
setOnCopyActionClickListener { field, protectedFieldView ->
|
||||
mEntryViewModel.requestCopyField(field, protectedFieldView)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,14 +231,14 @@ class EntryFragment: DatabaseFragment() {
|
||||
fun firstEntryFieldCopyView(): View? {
|
||||
return try {
|
||||
templateView.getActionImageView()
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun launchEntryCopyEducationAction() {
|
||||
val appNameString = getString(R.string.app_name)
|
||||
mClipboardHelper?.timeoutCopyToClipboard(appNameString, appNameString)
|
||||
mEntryViewModel.copyToClipboard(appNameString)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.kunzisoft.keepass.credentialprovider
|
||||
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.view.ProtectedFieldView
|
||||
|
||||
data class UserVerificationData(
|
||||
val actionType: UserVerificationActionType,
|
||||
val database: ContextualDatabase? = null,
|
||||
val entryId: NodeId<*>? = null,
|
||||
val field: Field? = null,
|
||||
val protectedFieldView: ProtectedFieldView? = null,
|
||||
val preferenceKey: String? = null
|
||||
)
|
||||
|
||||
enum class UserVerificationActionType {
|
||||
LAUNCH_PASSKEY_CEREMONY,
|
||||
SHOW_PROTECTED_FIELD,
|
||||
COPY_PROTECTED_FIELD,
|
||||
EDIT_ENTRY,
|
||||
EDIT_DATABASE_SETTING,
|
||||
MERGE_FROM_DATABASE,
|
||||
SAVE_DATABASE_COPY_TO
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.kunzisoft.keepass.credentialprovider
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
|
||||
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||
import androidx.biometric.BiometricManager.BIOMETRIC_SUCCESS
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.CheckDatabaseCredentialDialogFragment
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.UserVerificationRequirement
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil.isUserVerificationDeviceCredential
|
||||
import com.kunzisoft.keepass.utils.getEnumExtra
|
||||
import com.kunzisoft.keepass.utils.putEnumExtra
|
||||
import com.kunzisoft.keepass.view.ProtectedFieldView
|
||||
import com.kunzisoft.keepass.view.toastError
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
|
||||
class UserVerificationHelper {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_USER_VERIFICATION = "com.kunzisoft.keepass.extra.userVerification"
|
||||
private const val EXTRA_USER_VERIFIED_WITH_AUTH = "com.kunzisoft.keepass.extra.userVerifiedWithAuth"
|
||||
|
||||
/**
|
||||
* Allowed authenticators for the User Verification
|
||||
*/
|
||||
const val ALLOWED_AUTHENTICATORS = BIOMETRIC_WEAK or DEVICE_CREDENTIAL
|
||||
|
||||
/**
|
||||
* Check if the device supports the biometric prompt for User Verification
|
||||
*/
|
||||
fun Context.isAuthenticatorsAllowed(): Boolean {
|
||||
return BiometricManager.from(this)
|
||||
.canAuthenticate(ALLOWED_AUTHENTICATORS) == BIOMETRIC_SUCCESS
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the User Verification to the intent
|
||||
*/
|
||||
fun Intent.addUserVerification(
|
||||
userVerification: UserVerificationRequirement,
|
||||
userVerifiedWithAuth: Boolean
|
||||
) {
|
||||
putEnumExtra(EXTRA_USER_VERIFICATION, userVerification)
|
||||
putExtra(EXTRA_USER_VERIFIED_WITH_AUTH, userVerifiedWithAuth)
|
||||
}
|
||||
|
||||
/**
|
||||
* Define if the User is verified with authentification from the intent
|
||||
*/
|
||||
fun Intent.getUserVerifiedWithAuth(): Boolean {
|
||||
return getBooleanExtra(EXTRA_USER_VERIFIED_WITH_AUTH, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the User Verification from the intent
|
||||
*/
|
||||
fun Intent.removeUserVerification() {
|
||||
removeExtra(EXTRA_USER_VERIFICATION)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the User verified with auth from the intent
|
||||
*/
|
||||
fun Intent.removeUserVerifiedWithAuth() {
|
||||
removeExtra(EXTRA_USER_VERIFIED_WITH_AUTH)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the User Verification from the intent
|
||||
*/
|
||||
fun Intent.isUserVerificationNeeded(userVerificationPreferred: Boolean): Boolean {
|
||||
val userVerification: UserVerificationRequirement =
|
||||
getEnumExtra<UserVerificationRequirement>(EXTRA_USER_VERIFICATION)
|
||||
?: UserVerificationRequirement.PREFERRED
|
||||
return (userVerification == UserVerificationRequirement.REQUIRED
|
||||
|| (userVerificationPreferred
|
||||
&& userVerification == UserVerificationRequirement.PREFERRED)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the User needs to be verified for this entry
|
||||
*/
|
||||
fun EntryInfo.isUserVerificationNeeded(): Boolean {
|
||||
// Apply to any entry with protected content
|
||||
// Not only this.passkey != null
|
||||
return true
|
||||
}
|
||||
|
||||
fun Fragment.checkUserVerification(
|
||||
userVerificationViewModel: UserVerificationViewModel,
|
||||
dataToVerify: UserVerificationData
|
||||
) {
|
||||
activity?.checkUserVerification(userVerificationViewModel, dataToVerify)
|
||||
}
|
||||
|
||||
fun FragmentActivity.requestShowUnprotectField(
|
||||
userVerificationViewModel: UserVerificationViewModel,
|
||||
database: ContextualDatabase,
|
||||
protectedFieldView: ProtectedFieldView
|
||||
) {
|
||||
if (protectedFieldView.isCurrentlyProtected()) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = userVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.SHOW_PROTECTED_FIELD,
|
||||
database = database,
|
||||
protectedFieldView = protectedFieldView
|
||||
)
|
||||
)
|
||||
} else {
|
||||
protectedFieldView.protect()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a dialog to verify the user
|
||||
*/
|
||||
fun FragmentActivity.checkUserVerification(
|
||||
userVerificationViewModel: UserVerificationViewModel,
|
||||
dataToVerify: UserVerificationData
|
||||
) {
|
||||
if (isAuthenticatorsAllowed() && isUserVerificationDeviceCredential(this)) {
|
||||
showUserVerificationDeviceCredential(userVerificationViewModel, dataToVerify)
|
||||
} else if (dataToVerify.database != null) {
|
||||
showUserVerificationDatabaseCredential(userVerificationViewModel, dataToVerify)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a dialog for entering the device credential to be checked
|
||||
*/
|
||||
fun FragmentActivity.showUserVerificationDeviceCredential(
|
||||
userVerificationViewModel: UserVerificationViewModel,
|
||||
dataToVerify: UserVerificationData
|
||||
) {
|
||||
BiometricPrompt(
|
||||
this, ContextCompat.getMainExecutor(this),
|
||||
object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(
|
||||
errorCode: Int,
|
||||
errString: CharSequence
|
||||
) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
when (errorCode) {
|
||||
BiometricPrompt.ERROR_CANCELED,
|
||||
BiometricPrompt.ERROR_NEGATIVE_BUTTON,
|
||||
BiometricPrompt.ERROR_USER_CANCELED -> {
|
||||
// No operation
|
||||
Log.i("UserVerification", "$errString")
|
||||
}
|
||||
else -> {
|
||||
toastError(SecurityException("Authentication error: $errString"))
|
||||
}
|
||||
}
|
||||
userVerificationViewModel.onUserVerificationFailed(dataToVerify)
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(
|
||||
result: BiometricPrompt.AuthenticationResult
|
||||
) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
userVerificationViewModel.onUserVerificationSucceeded(dataToVerify)
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed()
|
||||
toastError(SecurityException(getString(R.string.device_unlock_not_recognized)))
|
||||
userVerificationViewModel.onUserVerificationFailed(dataToVerify)
|
||||
}
|
||||
}).authenticate(
|
||||
BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.user_verification_required_title))
|
||||
.setSubtitle(getString(R.string.user_verification_required_description))
|
||||
.setAllowedAuthenticators(ALLOWED_AUTHENTICATORS)
|
||||
.setConfirmationRequired(false)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a dialog for entering the database credential to be checked
|
||||
*/
|
||||
fun FragmentActivity.showUserVerificationDatabaseCredential(
|
||||
userVerificationViewModel: UserVerificationViewModel,
|
||||
dataToVerify: UserVerificationData
|
||||
) {
|
||||
userVerificationViewModel.dataToVerify = dataToVerify
|
||||
val fragmentTag = "checkDatabaseCredentialDialog"
|
||||
var fragment: CheckDatabaseCredentialDialogFragment? =
|
||||
supportFragmentManager.findFragmentByTag(fragmentTag)
|
||||
as? CheckDatabaseCredentialDialogFragment?
|
||||
if (fragment == null) {
|
||||
fragment = CheckDatabaseCredentialDialogFragment.getInstance()
|
||||
fragment.show(this.supportFragmentManager, fragmentTag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,9 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.FileDatabaseSelectActivity
|
||||
import com.kunzisoft.keepass.activities.GroupActivity
|
||||
@@ -43,7 +45,14 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addTypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.setActivityResult
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.addUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.getUserVerifiedWithAuth
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.isUserVerificationNeeded
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.AndroidPrivilegedApp
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.UserVerificationRequirement
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.addAppOrigin
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.addAuthCode
|
||||
import com.kunzisoft.keepass.credentialprovider.viewmodel.CredentialLauncherViewModel
|
||||
@@ -52,9 +61,11 @@ import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.model.AppOrigin
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil.isUserVerificationPreferred
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.AppUtil.randomRequestCode
|
||||
import com.kunzisoft.keepass.view.toastError
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
@@ -62,6 +73,7 @@ import java.util.UUID
|
||||
class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
|
||||
private val passkeyLauncherViewModel: PasskeyLauncherViewModel by viewModels()
|
||||
private val userVerificationViewModel: UserVerificationViewModel by viewModels()
|
||||
|
||||
private var mPasskeySelectionActivityResultLauncher: ActivityResultLauncher<Intent>? =
|
||||
this.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
@@ -83,9 +95,10 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
lifecycleScope.launch {
|
||||
// Initialize the parameters
|
||||
passkeyLauncherViewModel.initialize()
|
||||
passkeyLauncherViewModel.initialize(userVerified = intent.getUserVerifiedWithAuth())
|
||||
// Retrieve the UI
|
||||
passkeyLauncherViewModel.uiState.collect { uiState ->
|
||||
when (uiState) {
|
||||
@@ -161,11 +174,58 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
userVerificationViewModel.userVerificationState.collect { uiState ->
|
||||
when (uiState) {
|
||||
is UserVerificationViewModel.UVState.Loading -> {}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationSucceeded -> {
|
||||
val data = uiState.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.LAUNCH_PASSKEY_CEREMONY -> {
|
||||
passkeyLauncherViewModel.launchActionIfNeeded(
|
||||
userVerified = true,
|
||||
intent = intent,
|
||||
specialMode = mSpecialMode,
|
||||
database = uiState.dataToVerify.database
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
userVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationCanceled -> {
|
||||
toastError(uiState.error)
|
||||
passkeyLauncherViewModel.cancelResult()
|
||||
userVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnknownDatabaseRetrieved(database: ContextualDatabase?) {
|
||||
super.onUnknownDatabaseRetrieved(database)
|
||||
passkeyLauncherViewModel.launchActionIfNeeded(intent, mSpecialMode, database)
|
||||
// To manage https://github.com/Kunzisoft/KeePassDX/issues/2283
|
||||
val userVerificationNeeded = intent.isUserVerificationNeeded(
|
||||
userVerificationPreferred = isUserVerificationPreferred(this)
|
||||
) && intent.getUserVerifiedWithAuth().not()
|
||||
if (userVerificationNeeded) {
|
||||
checkUserVerification(
|
||||
userVerificationViewModel = userVerificationViewModel,
|
||||
dataToVerify = UserVerificationData(
|
||||
actionType = UserVerificationActionType.LAUNCH_PASSKEY_CEREMONY,
|
||||
database = database
|
||||
)
|
||||
)
|
||||
} else {
|
||||
passkeyLauncherViewModel.launchActionIfNeeded(
|
||||
intent = intent,
|
||||
specialMode = mSpecialMode,
|
||||
database = database
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDatabaseActionFinished(
|
||||
@@ -278,7 +338,9 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
specialMode: SpecialMode,
|
||||
searchInfo: SearchInfo? = null,
|
||||
appOrigin: AppOrigin? = null,
|
||||
nodeId: UUID? = null
|
||||
nodeId: UUID? = null,
|
||||
userVerification: UserVerificationRequirement = UserVerificationRequirement.PREFERRED,
|
||||
userVerifiedWithAuth: Boolean = true
|
||||
): PendingIntent? {
|
||||
return PendingIntent.getActivity(
|
||||
context,
|
||||
@@ -290,6 +352,7 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
addAppOrigin(appOrigin)
|
||||
addNodeId(nodeId)
|
||||
addAuthCode(nodeId)
|
||||
addUserVerification(userVerification, userVerifiedWithAuth)
|
||||
},
|
||||
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
@@ -154,7 +154,7 @@ class StructureParser(private val structure: AssistStructure) {
|
||||
it.contains(View.AUTOFILL_HINT_PASSWORD, true) -> {
|
||||
// Password Id changed if it's the second times we are here,
|
||||
// So the last username candidate is most appropriate
|
||||
if (result?.passwordId != null) {
|
||||
if (result?.passwordId != null && usernameIdCandidate != null) {
|
||||
result?.usernameId = usernameIdCandidate
|
||||
result?.usernameValue = usernameValueCandidate
|
||||
}
|
||||
|
||||
@@ -42,12 +42,14 @@ import androidx.credentials.provider.CredentialEntry
|
||||
import androidx.credentials.provider.CredentialProviderService
|
||||
import androidx.credentials.provider.ProviderClearCredentialStateRequest
|
||||
import androidx.credentials.provider.PublicKeyCredentialEntry
|
||||
import com.kunzisoft.encrypt.Base64Helper.Companion.b64Encode
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.buildIcon
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.activity.PasskeyLauncherActivity
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialCreationOptions
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialRequestOptions
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.UserVerificationRequirement
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.DatabaseTaskProvider
|
||||
import com.kunzisoft.keepass.database.exception.RegisterInReadOnlyDatabaseException
|
||||
@@ -90,9 +92,13 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun buildPasskeySearchInfo(relyingParty: String): SearchInfo {
|
||||
private fun buildPasskeySearchInfo(
|
||||
relyingParty: String,
|
||||
credentialIds: List<String> = listOf()
|
||||
): SearchInfo {
|
||||
return SearchInfo().apply {
|
||||
this.relyingParty = relyingParty
|
||||
this.credentialIds = credentialIds
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +114,7 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(javaClass.simpleName, "onBeginGetCredentialRequest error", e)
|
||||
toastError(e)
|
||||
callback.onError(GetCredentialUnknownException())
|
||||
}
|
||||
}
|
||||
@@ -136,12 +143,16 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
option: BeginGetPublicKeyCredentialOption,
|
||||
callback: (List<CredentialEntry>) -> Unit
|
||||
) {
|
||||
|
||||
val passkeyEntries: MutableList<CredentialEntry> = mutableListOf()
|
||||
|
||||
val relyingPartyId = PublicKeyCredentialRequestOptions(option.requestJson).rpId
|
||||
val searchInfo = buildPasskeySearchInfo(relyingPartyId)
|
||||
Log.d(TAG, "Build passkey search for relying party $relyingPartyId")
|
||||
val publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions(option.requestJson)
|
||||
val relyingPartyId = publicKeyCredentialRequestOptions.rpId
|
||||
val credentialIdList = publicKeyCredentialRequestOptions.allowCredentials
|
||||
.map { b64Encode(it.id) }
|
||||
val searchInfo = buildPasskeySearchInfo(relyingPartyId, credentialIdList)
|
||||
val userVerification = publicKeyCredentialRequestOptions.userVerification
|
||||
Log.d(TAG, "Build passkey search for UV $userVerification, " +
|
||||
"RP $relyingPartyId and Credential IDs $credentialIdList")
|
||||
SearchHelper.checkAutoSearchInfo(
|
||||
context = this,
|
||||
database = mDatabase,
|
||||
@@ -153,14 +164,19 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
nodeId = passkeyEntry.id,
|
||||
appOrigin = passkeyEntry.appOrigin
|
||||
appOrigin = passkeyEntry.appOrigin,
|
||||
userVerification = userVerification,
|
||||
userVerifiedWithAuth = false
|
||||
)?.let { usagePendingIntent ->
|
||||
val passkey = passkeyEntry.passkey
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
context = applicationContext,
|
||||
username = passkey?.username ?: "Unknown",
|
||||
icon = passkeyEntry.buildIcon(this@PasskeyProviderService, database)?.apply {
|
||||
icon = passkeyEntry.buildIcon(
|
||||
this@PasskeyProviderService,
|
||||
database
|
||||
)?.apply {
|
||||
setTintBlendMode(BlendMode.DST)
|
||||
} ?: defaultIcon,
|
||||
pendingIntent = usagePendingIntent,
|
||||
@@ -175,26 +191,38 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
},
|
||||
onItemNotFound = { _ ->
|
||||
Log.w(TAG, "No passkey found in the database with this relying party : $relyingPartyId")
|
||||
Log.d(TAG, "Add pending intent for passkey selection in opened database")
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
searchInfo = searchInfo
|
||||
)?.let { pendingIntent ->
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
context = applicationContext,
|
||||
username = getString(R.string.passkey_database_username),
|
||||
displayName = getString(R.string.passkey_selection_description),
|
||||
icon = defaultIcon,
|
||||
pendingIntent = pendingIntent,
|
||||
beginGetPublicKeyCredentialOption = option,
|
||||
lastUsedTime = Instant.now(),
|
||||
isAutoSelectAllowed = isAutoSelectAllowed
|
||||
if (credentialIdList.isEmpty()) {
|
||||
Log.d(TAG, "Add pending intent for passkey selection in opened database")
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
searchInfo = searchInfo,
|
||||
userVerification = userVerification,
|
||||
userVerifiedWithAuth = false
|
||||
)?.let { pendingIntent ->
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
context = applicationContext,
|
||||
username = getString(R.string.passkey_database_username),
|
||||
displayName = getString(R.string.passkey_selection_description),
|
||||
icon = defaultIcon,
|
||||
pendingIntent = pendingIntent,
|
||||
beginGetPublicKeyCredentialOption = option,
|
||||
lastUsedTime = Instant.now(),
|
||||
isAutoSelectAllowed = isAutoSelectAllowed
|
||||
)
|
||||
)
|
||||
}
|
||||
callback(passkeyEntries)
|
||||
} else {
|
||||
throw IOException(
|
||||
getString(
|
||||
R.string.error_passkey_credential_id,
|
||||
relyingPartyId,
|
||||
credentialIdList
|
||||
)
|
||||
)
|
||||
}
|
||||
callback(passkeyEntries)
|
||||
},
|
||||
onDatabaseClosed = {
|
||||
Log.d(TAG, "Add pending intent for passkey selection in closed database")
|
||||
@@ -202,7 +230,8 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
searchInfo = searchInfo
|
||||
searchInfo = searchInfo,
|
||||
userVerifiedWithAuth = true
|
||||
)?.let { pendingIntent ->
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
@@ -257,14 +286,17 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
|
||||
private fun MutableList<CreateEntry>.addPendingIntentCreationNewEntry(
|
||||
accountName: String,
|
||||
searchInfo: SearchInfo?
|
||||
searchInfo: SearchInfo?,
|
||||
userVerification: UserVerificationRequirement
|
||||
) {
|
||||
Log.d(TAG, "Add pending intent for registration in opened database to create new item")
|
||||
// TODO add a setting to directly store in a specific group
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.REGISTRATION,
|
||||
searchInfo = searchInfo
|
||||
searchInfo = searchInfo,
|
||||
userVerification = userVerification,
|
||||
userVerifiedWithAuth = false
|
||||
)?.let { pendingIntent ->
|
||||
this.add(
|
||||
CreateEntry(
|
||||
@@ -287,11 +319,13 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
getString(R.string.passkey_database_username)
|
||||
else databaseName
|
||||
val createEntries: MutableList<CreateEntry> = mutableListOf()
|
||||
val relyingPartyId = PublicKeyCredentialCreationOptions(
|
||||
val publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions(
|
||||
requestJson = request.requestJson,
|
||||
clientDataHash = request.clientDataHash
|
||||
).relyingPartyEntity.id
|
||||
)
|
||||
val relyingPartyId = publicKeyCredentialCreationOptions.relyingPartyEntity.id
|
||||
val searchInfo = buildPasskeySearchInfo(relyingPartyId)
|
||||
val userVerification = publicKeyCredentialCreationOptions.authenticatorSelection.userVerification
|
||||
Log.d(TAG, "Build passkey search for relying party $relyingPartyId")
|
||||
SearchHelper.checkAutoSearchInfo(
|
||||
context = this,
|
||||
@@ -302,7 +336,11 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
throw RegisterInReadOnlyDatabaseException()
|
||||
} else {
|
||||
// To create a new entry
|
||||
createEntries.addPendingIntentCreationNewEntry(accountName, searchInfo)
|
||||
createEntries.addPendingIntentCreationNewEntry(
|
||||
accountName = accountName,
|
||||
searchInfo = searchInfo,
|
||||
userVerification = userVerification
|
||||
)
|
||||
/* TODO Overwrite
|
||||
// To select an existing entry and permit an overwrite
|
||||
Log.w(TAG, "Passkey already registered")
|
||||
@@ -333,7 +371,11 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
if (database.isReadOnly) {
|
||||
throw RegisterInReadOnlyDatabaseException()
|
||||
} else {
|
||||
createEntries.addPendingIntentCreationNewEntry(accountName, searchInfo)
|
||||
createEntries.addPendingIntentCreationNewEntry(
|
||||
accountName = accountName,
|
||||
searchInfo = searchInfo,
|
||||
userVerification = userVerification
|
||||
)
|
||||
}
|
||||
callback(createEntries)
|
||||
},
|
||||
@@ -342,7 +384,8 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
Log.d(TAG, "Add pending intent for passkey registration in closed database")
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.REGISTRATION
|
||||
specialMode = SpecialMode.REGISTRATION,
|
||||
userVerifiedWithAuth = true
|
||||
)?.let { pendingIntent ->
|
||||
createEntries.add(
|
||||
CreateEntry(
|
||||
|
||||
@@ -16,7 +16,25 @@
|
||||
|
||||
package com.kunzisoft.keepass.credentialprovider.passkey.data
|
||||
|
||||
data class PublicKeyCredentialRpEntity(val name: String, val id: String)
|
||||
import com.kunzisoft.encrypt.Base64Helper
|
||||
import org.json.JSONObject
|
||||
|
||||
data class PublicKeyCredentialRpEntity(
|
||||
val name: String,
|
||||
val id: String
|
||||
) {
|
||||
companion object {
|
||||
fun JSONObject.getPublicKeyCredentialRpEntity(
|
||||
parameterName: String
|
||||
): PublicKeyCredentialRpEntity {
|
||||
val rpJson = this.getJSONObject(parameterName)
|
||||
return PublicKeyCredentialRpEntity(
|
||||
rpJson.getString("name"),
|
||||
rpJson.getString("id")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class PublicKeyCredentialUserEntity(
|
||||
val name: String,
|
||||
@@ -42,9 +60,41 @@ data class PublicKeyCredentialUserEntity(
|
||||
result = 31 * result + displayName.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun JSONObject.getPublicKeyCredentialUserEntity(
|
||||
parameterName: String
|
||||
): PublicKeyCredentialUserEntity {
|
||||
val rpUser = this.getJSONObject(parameterName)
|
||||
return PublicKeyCredentialUserEntity(
|
||||
rpUser.getString("name"),
|
||||
Base64Helper.b64Decode(rpUser.getString("id")),
|
||||
rpUser.getString("displayName")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class PublicKeyCredentialParameters(val type: String, val alg: Long)
|
||||
data class PublicKeyCredentialParameters(
|
||||
val type: String,
|
||||
val alg: Long
|
||||
) {
|
||||
companion object {
|
||||
fun JSONObject.getPublicKeyCredentialParametersList(
|
||||
parameterName: String
|
||||
): List<PublicKeyCredentialParameters> {
|
||||
val pubKeyCredParamsJson = this.getJSONArray(parameterName)
|
||||
val pubKeyCredParamsTmp: MutableList<PublicKeyCredentialParameters> = mutableListOf()
|
||||
for (i in 0 until pubKeyCredParamsJson.length()) {
|
||||
val e = pubKeyCredParamsJson.getJSONObject(i)
|
||||
pubKeyCredParamsTmp.add(
|
||||
PublicKeyCredentialParameters(e.getString("type"), e.getLong("alg"))
|
||||
)
|
||||
}
|
||||
return pubKeyCredParamsTmp.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class PublicKeyCredentialDescriptor(
|
||||
val type: String,
|
||||
@@ -70,11 +120,104 @@ data class PublicKeyCredentialDescriptor(
|
||||
result = 31 * result + transports.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun JSONObject.getPublicKeyCredentialDescriptorList(
|
||||
parameterName: String
|
||||
): List<PublicKeyCredentialDescriptor> {
|
||||
val credentialsJson = this.getJSONArray(parameterName)
|
||||
val credentialsTmp: MutableList<PublicKeyCredentialDescriptor> = mutableListOf()
|
||||
for (i in 0 until credentialsJson.length()) {
|
||||
val credentialJson = credentialsJson.getJSONObject(i)
|
||||
|
||||
val transports: MutableList<String> = mutableListOf()
|
||||
val transportsJson = credentialJson.getJSONArray("transports")
|
||||
for (j in 0 until transportsJson.length()) {
|
||||
transports.add(transportsJson.getString(j))
|
||||
}
|
||||
credentialsTmp.add(
|
||||
PublicKeyCredentialDescriptor(
|
||||
type = credentialJson.getString("type"),
|
||||
id = Base64Helper.b64Decode(credentialJson.getString("id")),
|
||||
transports = transports
|
||||
)
|
||||
)
|
||||
}
|
||||
return credentialsTmp.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webauthn-3/#dictdef-authenticatorselectioncriteria
|
||||
data class AuthenticatorSelectionCriteria(
|
||||
val authenticatorAttachment: String,
|
||||
val residentKey: String,
|
||||
val requireResidentKey: Boolean = false,
|
||||
val userVerification: String = "preferred"
|
||||
)
|
||||
val authenticatorAttachment: String? = null,
|
||||
val residentKey: ResidentKeyRequirement? = null,
|
||||
val requireResidentKey: Boolean?,
|
||||
val userVerification: UserVerificationRequirement = UserVerificationRequirement.PREFERRED
|
||||
) {
|
||||
companion object {
|
||||
fun JSONObject.getAuthenticatorSelectionCriteria(
|
||||
parameterName: String
|
||||
): AuthenticatorSelectionCriteria {
|
||||
val authenticatorSelection = this.optJSONObject(parameterName)
|
||||
?: return AuthenticatorSelectionCriteria(requireResidentKey = null)
|
||||
val authenticatorAttachment = if (!authenticatorSelection.isNull("authenticatorAttachment"))
|
||||
authenticatorSelection.getString("authenticatorAttachment") else null
|
||||
var residentKey = if (!authenticatorSelection.isNull("residentKey"))
|
||||
ResidentKeyRequirement.fromString(authenticatorSelection.getString("residentKey"))
|
||||
else null
|
||||
val requireResidentKey = authenticatorSelection.optBoolean("requireResidentKey", false)
|
||||
val userVerification = UserVerificationRequirement
|
||||
.fromString(authenticatorSelection.optString("userVerification", "preferred"))
|
||||
?: UserVerificationRequirement.PREFERRED
|
||||
// https://www.w3.org/TR/webauthn-3/#enumdef-residentkeyrequirement
|
||||
if (residentKey == null) {
|
||||
residentKey = if (requireResidentKey) {
|
||||
ResidentKeyRequirement.REQUIRED
|
||||
} else {
|
||||
ResidentKeyRequirement.DISCOURAGED
|
||||
}
|
||||
}
|
||||
return AuthenticatorSelectionCriteria(
|
||||
authenticatorAttachment = authenticatorAttachment,
|
||||
residentKey = residentKey,
|
||||
requireResidentKey = requireResidentKey,
|
||||
userVerification = userVerification
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webauthn-3/#enumdef-residentkeyrequirement
|
||||
enum class ResidentKeyRequirement(val value: String) {
|
||||
DISCOURAGED("discouraged"),
|
||||
PREFERRED("preferred"),
|
||||
REQUIRED("required");
|
||||
override fun toString(): String {
|
||||
return value
|
||||
}
|
||||
companion object {
|
||||
fun fromString(value: String): ResidentKeyRequirement? {
|
||||
return ResidentKeyRequirement.entries.firstOrNull {
|
||||
it.value.equals(other = value, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webauthn-3/#enumdef-userverificationrequirement
|
||||
enum class UserVerificationRequirement(val value: String) {
|
||||
REQUIRED("required"),
|
||||
PREFERRED("preferred"),
|
||||
DISCOURAGED("discouraged");
|
||||
override fun toString(): String {
|
||||
return value
|
||||
}
|
||||
companion object {
|
||||
fun fromString(value: String): UserVerificationRequirement? {
|
||||
return UserVerificationRequirement.entries.firstOrNull {
|
||||
it.value.equals(other = value, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,52 +20,42 @@
|
||||
package com.kunzisoft.keepass.credentialprovider.passkey.data
|
||||
|
||||
import com.kunzisoft.encrypt.Base64Helper
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.AuthenticatorSelectionCriteria.Companion.getAuthenticatorSelectionCriteria
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialDescriptor.Companion.getPublicKeyCredentialDescriptorList
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialParameters.Companion.getPublicKeyCredentialParametersList
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialRpEntity.Companion.getPublicKeyCredentialRpEntity
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialUserEntity.Companion.getPublicKeyCredentialUserEntity
|
||||
import org.json.JSONObject
|
||||
|
||||
class PublicKeyCredentialCreationOptions(
|
||||
requestJson: String,
|
||||
var clientDataHash: ByteArray?
|
||||
) {
|
||||
val json: JSONObject = JSONObject(requestJson)
|
||||
private val json: JSONObject = JSONObject(requestJson)
|
||||
|
||||
val relyingPartyEntity: PublicKeyCredentialRpEntity
|
||||
val userEntity: PublicKeyCredentialUserEntity
|
||||
val challenge: ByteArray
|
||||
val pubKeyCredParams: List<PublicKeyCredentialParameters>
|
||||
val relyingPartyEntity: PublicKeyCredentialRpEntity =
|
||||
json.getPublicKeyCredentialRpEntity("rp")
|
||||
|
||||
var timeout: Long
|
||||
var excludeCredentials: List<PublicKeyCredentialDescriptor>
|
||||
var authenticatorSelection: AuthenticatorSelectionCriteria
|
||||
var attestation: String
|
||||
val userEntity: PublicKeyCredentialUserEntity =
|
||||
json.getPublicKeyCredentialUserEntity("user")
|
||||
|
||||
init {
|
||||
val rpJson = json.getJSONObject("rp")
|
||||
relyingPartyEntity = PublicKeyCredentialRpEntity(rpJson.getString("name"), rpJson.getString("id"))
|
||||
val rpUser = json.getJSONObject("user")
|
||||
val userId = Base64Helper.b64Decode(rpUser.getString("id"))
|
||||
userEntity =
|
||||
PublicKeyCredentialUserEntity(
|
||||
rpUser.getString("name"),
|
||||
userId,
|
||||
rpUser.getString("displayName")
|
||||
)
|
||||
challenge = Base64Helper.b64Decode(json.getString("challenge"))
|
||||
val pubKeyCredParamsJson = json.getJSONArray("pubKeyCredParams")
|
||||
val pubKeyCredParamsTmp: MutableList<PublicKeyCredentialParameters> = mutableListOf()
|
||||
for (i in 0 until pubKeyCredParamsJson.length()) {
|
||||
val e = pubKeyCredParamsJson.getJSONObject(i)
|
||||
pubKeyCredParamsTmp.add(
|
||||
PublicKeyCredentialParameters(e.getString("type"), e.getLong("alg"))
|
||||
)
|
||||
}
|
||||
pubKeyCredParams = pubKeyCredParamsTmp.toList()
|
||||
val challenge: ByteArray =
|
||||
Base64Helper.b64Decode(json.getString("challenge"))
|
||||
|
||||
timeout = json.optLong("timeout", 0)
|
||||
// TODO: Fix excludeCredentials and authenticatorSelection
|
||||
excludeCredentials = emptyList()
|
||||
authenticatorSelection = AuthenticatorSelectionCriteria("platform", "required")
|
||||
attestation = json.optString("attestation", "none")
|
||||
}
|
||||
val pubKeyCredParams: List<PublicKeyCredentialParameters> =
|
||||
json.getPublicKeyCredentialParametersList("pubKeyCredParams")
|
||||
|
||||
var timeout: Long =
|
||||
json.optLong("timeout", 0)
|
||||
|
||||
var excludeCredentials: List<PublicKeyCredentialDescriptor> =
|
||||
json.getPublicKeyCredentialDescriptorList("excludeCredentials")
|
||||
|
||||
var authenticatorSelection: AuthenticatorSelectionCriteria =
|
||||
json.getAuthenticatorSelectionCriteria("authenticatorSelection")
|
||||
|
||||
var attestation: String =
|
||||
json.optString("attestation", "none")
|
||||
|
||||
companion object {
|
||||
private val TAG = PublicKeyCredentialCreationOptions::class.simpleName
|
||||
|
||||
@@ -20,12 +20,33 @@
|
||||
package com.kunzisoft.keepass.credentialprovider.passkey.data
|
||||
|
||||
import com.kunzisoft.encrypt.Base64Helper
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialDescriptor.Companion.getPublicKeyCredentialDescriptorList
|
||||
import org.json.JSONObject
|
||||
|
||||
// https://www.w3.org/TR/webauthn-3/#enumdef-residentkeyrequirement
|
||||
class PublicKeyCredentialRequestOptions(requestJson: String) {
|
||||
val json: JSONObject = JSONObject(requestJson)
|
||||
val challenge: ByteArray = Base64Helper.b64Decode(json.getString("challenge"))
|
||||
val timeout: Long = json.optLong("timeout", 0)
|
||||
val rpId: String = json.optString("rpId", "")
|
||||
val userVerification: String = json.optString("userVerification", "preferred")
|
||||
private val json: JSONObject = JSONObject(requestJson)
|
||||
|
||||
val challenge: ByteArray =
|
||||
Base64Helper.b64Decode(json.getString("challenge"))
|
||||
|
||||
val timeout: Long =
|
||||
json.optLong("timeout", 0)
|
||||
|
||||
val rpId: String =
|
||||
json.optString("rpId", "")
|
||||
|
||||
val allowCredentials: List<PublicKeyCredentialDescriptor> =
|
||||
json.getPublicKeyCredentialDescriptorList("allowCredentials")
|
||||
|
||||
val userVerification: UserVerificationRequirement =
|
||||
UserVerificationRequirement.fromString(
|
||||
json.optString("userVerification", "preferred"))
|
||||
?: UserVerificationRequirement.PREFERRED
|
||||
|
||||
// TODO Hints
|
||||
val hints: List<String> = listOf()
|
||||
|
||||
// TODO Extensions
|
||||
// val extensions: AuthenticationExtensionsClientInputs
|
||||
}
|
||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.credentialprovider.passkey.util
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
@@ -200,6 +201,28 @@ object PasskeyHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Passkey error response
|
||||
*/
|
||||
fun Activity.buildPasskeyErrorAndSetResult(
|
||||
resources: Resources,
|
||||
relyingPartyId: String?,
|
||||
credentialIds: List<String>
|
||||
) {
|
||||
val error = resources.getString(
|
||||
R.string.error_passkey_credential_id,
|
||||
relyingPartyId,
|
||||
credentialIds
|
||||
)
|
||||
Log.e(javaClass.name, error)
|
||||
Toast.makeText(
|
||||
this,
|
||||
error,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the timestamp and authentication code transmitted via PendingIntent
|
||||
*/
|
||||
@@ -471,6 +494,7 @@ object PasskeyHelper {
|
||||
*/
|
||||
fun buildCreatePublicKeyCredentialResponse(
|
||||
publicKeyCredentialCreationParameters: PublicKeyCredentialCreationParameters,
|
||||
userVerified: Boolean,
|
||||
backupEligibility: Boolean,
|
||||
backupState: Boolean
|
||||
): CreatePublicKeyCredentialResponse {
|
||||
@@ -488,7 +512,7 @@ object PasskeyHelper {
|
||||
keyTypeId = keyTypeId
|
||||
) ?: mapOf<Int, Any>()),
|
||||
userPresent = true,
|
||||
userVerified = true,
|
||||
userVerified = userVerified,
|
||||
backupEligibility = backupEligibility,
|
||||
backupState = backupState,
|
||||
publicKeyTypeId = keyTypeId,
|
||||
@@ -560,6 +584,7 @@ object PasskeyHelper {
|
||||
requestOptions: PublicKeyCredentialRequestOptions,
|
||||
clientDataResponse: ClientDataResponse,
|
||||
passkey: Passkey,
|
||||
userVerified: Boolean,
|
||||
defaultBackupEligibility: Boolean,
|
||||
defaultBackupState: Boolean
|
||||
): PublicKeyCredential {
|
||||
@@ -568,7 +593,7 @@ object PasskeyHelper {
|
||||
response = AuthenticatorAssertionResponse(
|
||||
requestOptions = requestOptions,
|
||||
userPresent = true,
|
||||
userVerified = true,
|
||||
userVerified = userVerified,
|
||||
backupEligibility = passkey.backupEligibility ?: defaultBackupEligibility,
|
||||
backupState = passkey.backupState ?: defaultBackupState,
|
||||
userHandle = passkey.userHandle,
|
||||
|
||||
@@ -24,7 +24,6 @@ abstract class CredentialLauncherViewModel(application: Application): AndroidVie
|
||||
|
||||
protected var isResultLauncherRegistered: Boolean = false
|
||||
private var mSelectionResult: ActivityResult? = null
|
||||
|
||||
protected val mCredentialUiState = MutableStateFlow<CredentialState>(CredentialState.Loading)
|
||||
val credentialUiState: StateFlow<CredentialState> = mCredentialUiState
|
||||
|
||||
@@ -56,7 +55,7 @@ abstract class CredentialLauncherViewModel(application: Application): AndroidVie
|
||||
)
|
||||
}
|
||||
|
||||
private fun onDatabaseRetrieved(database: ContextualDatabase) {
|
||||
fun onDatabaseRetrieved(database: ContextualDatabase) {
|
||||
mDatabase = database
|
||||
mSelectionResult?.let { selectionResult ->
|
||||
manageSelectionResult(database, selectionResult)
|
||||
|
||||
@@ -64,14 +64,16 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
private var mPasskey: Passkey? = null
|
||||
|
||||
private var mLockDatabaseAfterSelection: Boolean = false
|
||||
private var mUserVerified: Boolean = true
|
||||
private var mBackupEligibility: Boolean = true
|
||||
private var mBackupState: Boolean = false
|
||||
|
||||
private val mUiState = MutableStateFlow<UIState>(UIState.Loading)
|
||||
val uiState: StateFlow<UIState> = mUiState
|
||||
|
||||
fun initialize() {
|
||||
fun initialize(userVerified: Boolean) {
|
||||
mLockDatabaseAfterSelection = PreferencesUtil.isPasskeyCloseDatabaseEnable(getApplication())
|
||||
mUserVerified = userVerified
|
||||
mBackupEligibility = PreferencesUtil.isPasskeyBackupEligibilityEnable(getApplication())
|
||||
mBackupState = PreferencesUtil.isPasskeyBackupStateEnable(getApplication())
|
||||
}
|
||||
@@ -149,6 +151,16 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
}
|
||||
}
|
||||
|
||||
fun launchActionIfNeeded(
|
||||
userVerified: Boolean,
|
||||
intent: Intent,
|
||||
specialMode: SpecialMode,
|
||||
database: ContextualDatabase?
|
||||
) {
|
||||
this.mUserVerified = userVerified
|
||||
launchActionIfNeeded(intent, specialMode, database)
|
||||
}
|
||||
|
||||
override fun launchActionIfNeeded(
|
||||
intent: Intent,
|
||||
specialMode: SpecialMode,
|
||||
@@ -307,6 +319,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
appOrigin = appOrigin
|
||||
),
|
||||
passkey = passkey,
|
||||
userVerified = mUserVerified,
|
||||
defaultBackupEligibility = mBackupEligibility,
|
||||
defaultBackupState = mBackupState
|
||||
)
|
||||
@@ -363,6 +376,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
appOrigin = appOrigin
|
||||
),
|
||||
passkey = passkey,
|
||||
userVerified = mUserVerified,
|
||||
defaultBackupEligibility = mBackupEligibility,
|
||||
defaultBackupState = mBackupState
|
||||
)
|
||||
@@ -505,6 +519,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
intent = responseIntent,
|
||||
response = buildCreatePublicKeyCredentialResponse(
|
||||
publicKeyCredentialCreationParameters = it,
|
||||
userVerified = mUserVerified,
|
||||
backupEligibility = passkey?.backupEligibility
|
||||
?: mBackupEligibility,
|
||||
backupState = passkey?.backupState
|
||||
|
||||
@@ -238,7 +238,7 @@ class DatabaseTaskProvider(
|
||||
|
||||
try {
|
||||
context.unregisterReceiver(databaseTaskBroadcastReceiver)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// If receiver not register, do nothing
|
||||
}
|
||||
}
|
||||
@@ -319,7 +319,6 @@ class DatabaseTaskProvider(
|
||||
databaseUri: Uri,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
|
||||
start(Bundle().apply {
|
||||
putParcelable(DatabaseTaskNotificationService.DATABASE_URI_KEY, databaseUri)
|
||||
putParcelable(DatabaseTaskNotificationService.MAIN_CREDENTIAL_KEY, mainCredential)
|
||||
|
||||
@@ -94,6 +94,7 @@ object SearchHelper {
|
||||
callback.invoke(
|
||||
SearchParameters().apply {
|
||||
searchQuery = query
|
||||
searchOptions = optionsString()
|
||||
allowEmptyQuery = false
|
||||
searchInTitles = false
|
||||
searchInUsernames = false
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.GroupActivity
|
||||
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||
import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.MainCredential
|
||||
import com.kunzisoft.keepass.database.ProgressMessage
|
||||
@@ -61,7 +62,6 @@ import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.credentialprovider.activity.HardwareKeyActivity
|
||||
import com.kunzisoft.keepass.model.CipherEncryptDatabase
|
||||
import com.kunzisoft.keepass.model.SnapFileDatabaseInfo
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
@@ -917,7 +917,7 @@ open class DatabaseTaskNotificationService : LockNotificationService(), Progress
|
||||
|
||||
private fun buildDatabaseAssignCredentialActionTask(
|
||||
intent: Intent,
|
||||
database: ContextualDatabase,
|
||||
database: ContextualDatabase
|
||||
): ActionRunnable? {
|
||||
return if (intent.hasExtra(DATABASE_URI_KEY)
|
||||
&& intent.hasExtra(MAIN_CREDENTIAL_KEY)
|
||||
|
||||
@@ -302,7 +302,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
||||
biometricUnlockEnablePreference.isChecked = false
|
||||
warningMessage(activity, keystoreWarning = true, deleteKeys = true) {
|
||||
biometricUnlockEnablePreference.isChecked = true
|
||||
deviceCredentialUnlockEnablePreference?.isChecked = false
|
||||
deviceCredentialUnlockEnablePreference.isChecked = false
|
||||
}
|
||||
} else {
|
||||
biometricUnlockEnablePreference.isChecked = false
|
||||
@@ -349,7 +349,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
||||
deviceCredentialUnlockEnablePreference.isChecked = false
|
||||
warningMessage(activity, keystoreWarning = true, deleteKeys = true) {
|
||||
deviceCredentialUnlockEnablePreference.isChecked = true
|
||||
biometricUnlockEnablePreference?.isChecked = false
|
||||
biometricUnlockEnablePreference.isChecked = false
|
||||
}
|
||||
} else {
|
||||
deviceCredentialUnlockEnablePreference.isChecked = false
|
||||
@@ -412,7 +412,6 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
||||
}
|
||||
warningAlertDialog = AlertDialog.Builder(activity)
|
||||
.setMessage(message)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setPositiveButton(resources.getString(android.R.string.ok)
|
||||
) { _, _ ->
|
||||
validate?.invoke()
|
||||
@@ -524,27 +523,23 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
||||
}
|
||||
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||
|
||||
var otherDialogFragment = false
|
||||
|
||||
var dialogFragment: DialogFragment? = null
|
||||
// Main Preferences
|
||||
|
||||
when (preference.key) {
|
||||
getString(R.string.app_timeout_key),
|
||||
getString(R.string.clipboard_timeout_key),
|
||||
getString(R.string.temp_device_unlock_timeout_key) -> {
|
||||
dialogFragment = DurationDialogFragmentCompat.newInstance(preference.key)
|
||||
}
|
||||
else -> otherDialogFragment = true
|
||||
else -> {}
|
||||
}
|
||||
|
||||
if (dialogFragment != null) {
|
||||
@Suppress("DEPRECATION")
|
||||
dialogFragment.setTargetFragment(this, 0)
|
||||
dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT)
|
||||
}
|
||||
// Could not be handled here. Try with the super method.
|
||||
else if (otherDialogFragment) {
|
||||
} else {
|
||||
// Could not be handled here. Try with the super method.
|
||||
super.onDisplayPreferenceDialog(preference)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
|
||||
import com.kunzisoft.keepass.activities.legacy.DatabaseRetrieval
|
||||
import com.kunzisoft.keepass.activities.legacy.resetAppTimeoutWhenViewTouchedOrFocused
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationActionType
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationHelper.Companion.checkUserVerification
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.database.crypto.kdf.KdfEngine
|
||||
@@ -74,11 +77,16 @@ import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.utils.getParcelableCompat
|
||||
import com.kunzisoft.keepass.utils.getSerializableCompat
|
||||
import com.kunzisoft.keepass.viewmodels.DatabaseViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.SettingsViewModel
|
||||
import com.kunzisoft.keepass.viewmodels.UserVerificationViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetrieval {
|
||||
|
||||
private val mSettingsViewModel: SettingsViewModel by activityViewModels()
|
||||
private val mDatabaseViewModel: DatabaseViewModel by activityViewModels()
|
||||
private val mUserVerificationViewModel: UserVerificationViewModel by activityViewModels()
|
||||
|
||||
private val mDatabase: ContextualDatabase?
|
||||
get() = mDatabaseViewModel.database
|
||||
private var mDatabaseReadOnly: Boolean = false
|
||||
@@ -171,6 +179,51 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mUserVerificationViewModel.userVerificationState.collect { state ->
|
||||
when (state) {
|
||||
is UserVerificationViewModel.UVState.Loading -> {}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationCanceled -> {
|
||||
mSettingsViewModel.showError(state.error)
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
is UserVerificationViewModel.UVState.OnUserVerificationSucceeded -> {
|
||||
val data = state.dataToVerify
|
||||
when (data.actionType) {
|
||||
UserVerificationActionType.EDIT_DATABASE_SETTING -> {
|
||||
val database = data.database
|
||||
val preferenceKey = data.preferenceKey
|
||||
if (database != null && preferenceKey != null) {
|
||||
// Main Preferences
|
||||
when (preferenceKey) {
|
||||
// Master Key
|
||||
getString(R.string.settings_database_change_credentials_key) -> {
|
||||
SetMainCredentialDialogFragment
|
||||
.getInstance(database.allowNoMasterKey)
|
||||
.show(parentFragmentManager, "passwordDialog")
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
// TODO Settings in compose
|
||||
@Suppress("DEPRECATION")
|
||||
mSettingsViewModel.dialogFragment?.let { dialogFragment ->
|
||||
dialogFragment.setTargetFragment(
|
||||
this@NestedDatabaseSettingsFragment, 0
|
||||
)
|
||||
dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT)
|
||||
}
|
||||
mSettingsViewModel.dialogFragment = null
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
mUserVerificationViewModel.onUserVerificationReceived()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -325,7 +378,6 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
}
|
||||
// Change the recycle bin group
|
||||
recycleBinGroupPref?.setOnPreferenceClickListener {
|
||||
|
||||
true
|
||||
}
|
||||
// Recycle Bin group
|
||||
@@ -431,11 +483,18 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
}
|
||||
|
||||
private fun onCreateDatabaseMasterKeyPreference(database: ContextualDatabase) {
|
||||
findPreference<Preference>(getString(R.string.settings_database_change_credentials_key))?.apply {
|
||||
val changeCredentialKey = getString(R.string.settings_database_change_credentials_key)
|
||||
findPreference<Preference>(changeCredentialKey)?.apply {
|
||||
isEnabled = if (!mDatabaseReadOnly) {
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
SetMainCredentialDialogFragment.getInstance(database.allowNoMasterKey)
|
||||
.show(parentFragmentManager, "passwordDialog")
|
||||
checkUserVerification(
|
||||
mUserVerificationViewModel,
|
||||
UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_DATABASE_SETTING,
|
||||
database = database,
|
||||
preferenceKey = changeCredentialKey
|
||||
)
|
||||
)
|
||||
false
|
||||
}
|
||||
true
|
||||
@@ -462,7 +521,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
// To reassign color listener after orientation change
|
||||
val chromaDialog = parentFragmentManager.findFragmentByTag(TAG_PREF_FRAGMENT) as DatabaseColorPreferenceDialogFragmentCompat?
|
||||
chromaDialog?.onColorSelectedListener = colorSelectedListener
|
||||
} catch (e: Exception) {}
|
||||
} catch (_: Exception) {}
|
||||
|
||||
return view
|
||||
}
|
||||
@@ -730,9 +789,15 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
}
|
||||
|
||||
if (dialogFragment != null && !mDatabaseReadOnly) {
|
||||
@Suppress("DEPRECATION")
|
||||
dialogFragment.setTargetFragment(this, 0)
|
||||
dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT)
|
||||
mSettingsViewModel.dialogFragment = dialogFragment
|
||||
checkUserVerification(
|
||||
mUserVerificationViewModel,
|
||||
UserVerificationData(
|
||||
actionType = UserVerificationActionType.EDIT_DATABASE_SETTING,
|
||||
database = mDatabase,
|
||||
preferenceKey = preference.key
|
||||
)
|
||||
)
|
||||
}
|
||||
// Could not be handled here. Try with the super method.
|
||||
else if (otherDialogFragment) {
|
||||
@@ -742,7 +807,6 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment(), DatabaseRetriev
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
context?.let { context ->
|
||||
mDatabaseAutoSaveEnabled = PreferencesUtil.isAutoSaveDatabaseEnabled(context)
|
||||
}
|
||||
|
||||
@@ -30,11 +30,17 @@ import com.kunzisoft.keepass.activities.dialogs.UnderDevelopmentFeatureDialogFra
|
||||
abstract class NestedSettingsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
enum class Screen {
|
||||
APPLICATION, FORM_FILLING, DEVICE_UNLOCK, APPEARANCE, DATABASE, DATABASE_SECURITY, DATABASE_MASTER_KEY
|
||||
APPLICATION,
|
||||
FORM_FILLING,
|
||||
DEVICE_UNLOCK,
|
||||
APPEARANCE,
|
||||
DATABASE,
|
||||
DATABASE_SECURITY,
|
||||
DATABASE_MASTER_KEY
|
||||
}
|
||||
|
||||
fun getScreen(): Screen {
|
||||
return Screen.values()[requireArguments().getInt(TAG_KEY)]
|
||||
return Screen.entries[requireArguments().getInt(TAG_KEY)]
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
@@ -50,8 +56,7 @@ abstract class NestedSettingsFragment : PreferenceFragmentCompat() {
|
||||
preferenceInDev.setOnPreferenceClickListener { preference ->
|
||||
try { // don't check if we can
|
||||
(preference as TwoStatePreference).isChecked = false
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
UnderDevelopmentFeatureDialogFragment().show(parentFragmentManager, "underDevFeatureDialog")
|
||||
false
|
||||
}
|
||||
|
||||
@@ -132,12 +132,6 @@ object PreferencesUtil {
|
||||
context.resources.getBoolean(R.bool.hide_templates_default))
|
||||
}
|
||||
|
||||
fun hideProtectedValue(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.hide_password_key),
|
||||
context.resources.getBoolean(R.bool.hide_password_default))
|
||||
}
|
||||
|
||||
fun colorizePassword(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.colorize_password_key),
|
||||
@@ -696,6 +690,18 @@ object PreferencesUtil {
|
||||
context.resources.getBoolean(R.bool.passkeys_close_database_default))
|
||||
}
|
||||
|
||||
fun isUserVerificationDeviceCredential(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.user_verification_device_credential_key),
|
||||
context.resources.getBoolean(R.bool.user_verification_device_credential_default))
|
||||
}
|
||||
|
||||
fun isUserVerificationPreferred(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.user_verification_preferred_key),
|
||||
context.resources.getBoolean(R.bool.user_verification_preferred_default))
|
||||
}
|
||||
|
||||
fun isPasskeyBackupEligibilityEnable(context: Context): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
return prefs.getBoolean(context.getString(R.string.passkeys_backup_eligibility_key),
|
||||
@@ -882,7 +888,6 @@ object PreferencesUtil {
|
||||
context.getString(R.string.show_entry_colors_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.hide_expired_entries_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.hide_templates_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.hide_password_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.colorize_password_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.list_entries_show_username_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
context.getString(R.string.list_groups_show_number_entries_key) -> editor.putBoolean(name, value.toBoolean())
|
||||
|
||||
@@ -28,9 +28,13 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
|
||||
@@ -41,6 +45,9 @@ import com.kunzisoft.keepass.database.MainCredential
|
||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||
import com.kunzisoft.keepass.view.showActionErrorIfNeeded
|
||||
import com.kunzisoft.keepass.view.showError
|
||||
import com.kunzisoft.keepass.viewmodels.SettingsViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.joda.time.DateTime
|
||||
import java.util.Properties
|
||||
|
||||
@@ -49,6 +56,8 @@ open class SettingsActivity
|
||||
MainPreferenceFragment.Callback,
|
||||
SetMainCredentialDialogFragment.AssignMainCredentialDialogListener {
|
||||
|
||||
private val mSettingsViewModel: SettingsViewModel by viewModels()
|
||||
|
||||
private var backupManager: BackupManager? = null
|
||||
private var mExternalFileHelper: ExternalFileHelper? = null
|
||||
|
||||
@@ -118,7 +127,7 @@ open class SettingsActivity
|
||||
if (savedInstanceState?.getString(TITLE_KEY).isNullOrEmpty())
|
||||
toolbar?.setTitle(R.string.settings)
|
||||
else
|
||||
toolbar?.title = savedInstanceState?.getString(TITLE_KEY)
|
||||
toolbar?.title = savedInstanceState.getString(TITLE_KEY)
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
@@ -145,6 +154,20 @@ open class SettingsActivity
|
||||
// Eat state
|
||||
intent.removeExtra(FRAGMENT_ARG)
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mSettingsViewModel.settingsState.collect { settingsState ->
|
||||
when (settingsState) {
|
||||
is SettingsViewModel.SettingsState.Wait -> {}
|
||||
is SettingsViewModel.SettingsState.ShowError -> {
|
||||
coordinatorLayout?.showError(settingsState.error)
|
||||
mSettingsViewModel.errorShown()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ package com.kunzisoft.keepass.view
|
||||
|
||||
import android.content.Context
|
||||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.TextWatcher
|
||||
@@ -51,7 +50,6 @@ class PasswordEditView @JvmOverloads constructor(context: Context,
|
||||
|
||||
private var mViewHint: String = ""
|
||||
private var mMaxLines: Int = 3
|
||||
private var mShowPassword: Boolean = false
|
||||
|
||||
private var mPasswordTextWatchers: MutableList<TextWatcher> = mutableListOf()
|
||||
private var mPasswordTextWatcher: TextWatcher? = null
|
||||
@@ -65,8 +63,6 @@ class PasswordEditView @JvmOverloads constructor(context: Context,
|
||||
mViewHint = getString(R.styleable.PasswordView_passwordHint)
|
||||
?: context.getString(R.string.password)
|
||||
mMaxLines = getInteger(R.styleable.PasswordView_passwordMaxLines, mMaxLines)
|
||||
mShowPassword = getBoolean(R.styleable.PasswordView_passwordVisible,
|
||||
!PreferencesUtil.hideProtectedValue(context))
|
||||
} finally {
|
||||
recycle()
|
||||
}
|
||||
@@ -76,16 +72,12 @@ class PasswordEditView @JvmOverloads constructor(context: Context,
|
||||
inflater?.inflate(R.layout.view_password_edit, this)
|
||||
|
||||
passwordInputLayout = findViewById(R.id.password_edit_input_layout)
|
||||
passwordInputLayout?.hint = mViewHint
|
||||
passwordInputLayout.hint = mViewHint
|
||||
passwordText = findViewById(R.id.password_edit_text)
|
||||
if (mShowPassword) {
|
||||
passwordText?.inputType = passwordText.inputType or
|
||||
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
}
|
||||
passwordText?.maxLines = mMaxLines
|
||||
passwordText?.applyFontVisibility()
|
||||
passwordText.maxLines = mMaxLines
|
||||
passwordText.applyFontVisibility()
|
||||
passwordStrengthProgress = findViewById(R.id.password_edit_strength_progress)
|
||||
passwordStrengthProgress?.apply {
|
||||
passwordStrengthProgress.apply {
|
||||
setIndicatorColor(PasswordEntropy.Strength.RISKY.color)
|
||||
progress = 0
|
||||
max = 100
|
||||
@@ -93,7 +85,7 @@ class PasswordEditView @JvmOverloads constructor(context: Context,
|
||||
passwordEntropy = findViewById(R.id.password_edit_entropy)
|
||||
|
||||
mPasswordEntropyCalculator = PasswordEntropy {
|
||||
passwordText?.text?.toString()?.let { firstPassword ->
|
||||
passwordText.text?.toString()?.let { firstPassword ->
|
||||
getEntropyStrength(firstPassword)
|
||||
}
|
||||
}
|
||||
@@ -119,7 +111,7 @@ class PasswordEditView @JvmOverloads constructor(context: Context,
|
||||
PasswordGenerator.colorizedPassword(editable)
|
||||
}
|
||||
}
|
||||
passwordText?.addTextChangedListener(mPasswordTextWatcher)
|
||||
passwordText.addTextChangedListener(mPasswordTextWatcher)
|
||||
}
|
||||
|
||||
private fun getEntropyStrength(passwordText: String) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.kunzisoft.keepass.view
|
||||
|
||||
import android.view.View.OnClickListener
|
||||
|
||||
interface ProtectedFieldView {
|
||||
fun setProtection(
|
||||
protection: Boolean,
|
||||
isCurrentlyProtected: Boolean,
|
||||
onUnprotectClickListener: OnClickListener?
|
||||
)
|
||||
fun isCurrentlyProtected(): Boolean
|
||||
fun protect()
|
||||
fun unprotect()
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2025 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePassDX.
|
||||
*
|
||||
* KeePassDX is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* KeePassDX is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.view
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.Parcelable.Creator
|
||||
import android.util.AttributeSet
|
||||
import android.widget.RelativeLayout
|
||||
import com.kunzisoft.keepass.utils.readBooleanCompat
|
||||
import com.kunzisoft.keepass.utils.writeBooleanCompat
|
||||
|
||||
|
||||
abstract class ProtectedTextFieldView @JvmOverloads constructor(context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyle: Int = 0)
|
||||
: RelativeLayout(context, attrs, defStyle),
|
||||
GenericTextFieldView, ProtectedFieldView {
|
||||
|
||||
var isProtected: Boolean = false
|
||||
private set
|
||||
private var mIsCurrentlyProtected: Boolean = true
|
||||
|
||||
// Only to fix rebuild view from template
|
||||
var onSaveInstanceState: (() -> Unit)? = null
|
||||
|
||||
override fun isCurrentlyProtected(): Boolean {
|
||||
return mIsCurrentlyProtected
|
||||
}
|
||||
|
||||
override fun protect() {
|
||||
mIsCurrentlyProtected = true
|
||||
changeProtectedValueParameters()
|
||||
}
|
||||
|
||||
override fun unprotect() {
|
||||
mIsCurrentlyProtected = false
|
||||
changeProtectedValueParameters()
|
||||
}
|
||||
|
||||
override fun setProtection(
|
||||
protection: Boolean,
|
||||
isCurrentlyProtected: Boolean,
|
||||
onUnprotectClickListener: OnClickListener?
|
||||
) {
|
||||
this.isProtected = protection
|
||||
this.mIsCurrentlyProtected = isCurrentlyProtected
|
||||
if (isProtected) {
|
||||
changeProtectedValueParameters()
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun changeProtectedValueParameters()
|
||||
|
||||
override fun onSaveInstanceState(): Parcelable? {
|
||||
onSaveInstanceState?.invoke()
|
||||
return ProtectionState(super.onSaveInstanceState()).apply {
|
||||
this.isCurrentlyProtected = isCurrentlyProtected()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(state: Parcelable?) {
|
||||
when (state) {
|
||||
is ProtectionState -> {
|
||||
super.onRestoreInstanceState(state.superState)
|
||||
mIsCurrentlyProtected = state.isCurrentlyProtected
|
||||
}
|
||||
else -> super.onRestoreInstanceState(state)
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProtectionState : BaseSavedState {
|
||||
|
||||
var isCurrentlyProtected: Boolean = true
|
||||
|
||||
constructor(superState: Parcelable?) : super(superState)
|
||||
|
||||
private constructor(parcel: Parcel) : super(parcel) {
|
||||
isCurrentlyProtected = parcel.readBooleanCompat()
|
||||
}
|
||||
|
||||
override fun writeToParcel(out: Parcel, flags: Int) {
|
||||
super.writeToParcel(out, flags)
|
||||
out.writeBooleanCompat(isCurrentlyProtected)
|
||||
}
|
||||
|
||||
companion object CREATOR : Creator<ProtectionState> {
|
||||
override fun createFromParcel(parcel: Parcel): ProtectionState {
|
||||
return ProtectionState(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ProtectionState?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import com.kunzisoft.keepass.otp.OtpElement
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
import com.kunzisoft.keepass.utils.KeyboardUtil.hideKeyboard
|
||||
import com.kunzisoft.keepass.utils.readListCompat
|
||||
import com.kunzisoft.keepass.utils.readParcelableCompat
|
||||
|
||||
|
||||
@@ -45,11 +46,12 @@ abstract class TemplateAbstractView<
|
||||
private var mTemplate: Template? = null
|
||||
protected var mEntryInfo: EntryInfo? = null
|
||||
|
||||
// To keep unprotected views during orientation change
|
||||
protected var mUnprotectedFields = mutableListOf<Field>()
|
||||
|
||||
private var mViewFields = mutableListOf<ViewField>()
|
||||
|
||||
protected var mFontInVisibility: Boolean = PreferencesUtil.fieldFontIsInVisibility(context)
|
||||
protected var mHideProtectedValue: Boolean = PreferencesUtil.hideProtectedValue(context)
|
||||
|
||||
protected var headerContainerView: ViewGroup
|
||||
protected var entryIconView: ImageView
|
||||
protected var backgroundColorView: View
|
||||
@@ -121,9 +123,6 @@ abstract class TemplateAbstractView<
|
||||
}
|
||||
|
||||
private fun buildTemplate() {
|
||||
// Retrieve preferences
|
||||
mHideProtectedValue = PreferencesUtil.hideProtectedValue(context)
|
||||
|
||||
// Build each template section
|
||||
titleContainerView.removeAllViews()
|
||||
templateContainerView.removeAllViews()
|
||||
@@ -284,10 +283,6 @@ abstract class TemplateAbstractView<
|
||||
this.mFontInVisibility = fontInVisibility
|
||||
}
|
||||
|
||||
fun setHideProtectedValue(hideProtectedValue: Boolean) {
|
||||
this.mHideProtectedValue = hideProtectedValue
|
||||
}
|
||||
|
||||
fun setEntryInfo(entryInfo: EntryInfo?) {
|
||||
mEntryInfo = entryInfo
|
||||
buildTemplateAndPopulateInfo()
|
||||
@@ -578,7 +573,7 @@ abstract class TemplateAbstractView<
|
||||
}
|
||||
|
||||
return if (!isStandardFieldName(customField.name)) {
|
||||
customFieldsContainerView.visibility = View.VISIBLE
|
||||
customFieldsContainerView.visibility = VISIBLE
|
||||
if (getIndexViewFieldByName(customField.name) >= 0) {
|
||||
// Update a custom field with a new value,
|
||||
// new field name must be the same as old field name
|
||||
@@ -683,6 +678,16 @@ abstract class TemplateAbstractView<
|
||||
putCustomField(Field(otpField.name, otpField.protectedValue))
|
||||
}
|
||||
|
||||
fun saveUnprotectedFieldState(field: Field, isCurrentlyProtected: Boolean) {
|
||||
try {
|
||||
if (!isCurrentlyProtected) {
|
||||
mUnprotectedFields.add(field)
|
||||
} else {
|
||||
mUnprotectedFields.remove(field)
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(state: Parcelable?) {
|
||||
//begin boilerplate code so parent classes can restore state
|
||||
if (state !is SavedState) {
|
||||
@@ -691,6 +696,7 @@ abstract class TemplateAbstractView<
|
||||
} else {
|
||||
mTemplate = state.template
|
||||
mEntryInfo = state.entryInfo
|
||||
mUnprotectedFields = state.unprotectedFields
|
||||
onRestoreEntryInstanceState(state)
|
||||
buildTemplateAndPopulateInfo()
|
||||
super.onRestoreInstanceState(state.superState)
|
||||
@@ -706,6 +712,7 @@ abstract class TemplateAbstractView<
|
||||
retrieveDefaultValues = false)
|
||||
saveState.template = this.mTemplate
|
||||
saveState.entryInfo = this.mEntryInfo
|
||||
saveState.unprotectedFields = this.mUnprotectedFields
|
||||
onSaveEntryInstanceState(saveState)
|
||||
return saveState
|
||||
}
|
||||
@@ -715,6 +722,7 @@ abstract class TemplateAbstractView<
|
||||
protected class SavedState : BaseSavedState {
|
||||
var template: Template? = null
|
||||
var entryInfo: EntryInfo? = null
|
||||
var unprotectedFields = mutableListOf<Field>()
|
||||
// TODO Move
|
||||
var tempDateTimeViewId: Int? = null
|
||||
|
||||
@@ -723,6 +731,7 @@ abstract class TemplateAbstractView<
|
||||
private constructor(parcel: Parcel) : super(parcel) {
|
||||
template = parcel.readParcelableCompat() ?: template
|
||||
entryInfo = parcel.readParcelableCompat() ?: entryInfo
|
||||
parcel.readListCompat<Field>(unprotectedFields)
|
||||
val dateTimeViewId = parcel.readInt()
|
||||
if (dateTimeViewId != -1)
|
||||
tempDateTimeViewId = dateTimeViewId
|
||||
@@ -732,6 +741,7 @@ abstract class TemplateAbstractView<
|
||||
super.writeToParcel(out, flags)
|
||||
out.writeParcelable(template, flags)
|
||||
out.writeParcelable(entryInfo, flags)
|
||||
out.writeList(unprotectedFields)
|
||||
out.writeInt(tempDateTimeViewId ?: -1)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ import com.kunzisoft.keepass.database.element.template.TemplateAttributeAction
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||
import com.kunzisoft.keepass.database.helper.getLocalizedName
|
||||
import com.kunzisoft.keepass.database.helper.isStandardPasswordName
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField
|
||||
import com.kunzisoft.keepass.model.DataDate
|
||||
import com.kunzisoft.keepass.model.DataTime
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields
|
||||
|
||||
@@ -35,6 +35,11 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
@IdRes
|
||||
private var mTempDateTimeViewId: Int? = null
|
||||
|
||||
private var mOnUnprotectClickListener: ((Field, ProtectedFieldView) -> Unit)? = null
|
||||
fun setOnUnprotectClickListener(listener: ((Field, ProtectedFieldView) -> Unit)?) {
|
||||
this.mOnUnprotectClickListener = listener
|
||||
}
|
||||
|
||||
private var mOnCustomEditionActionClickListener: ((Field) -> Unit)? = null
|
||||
fun setOnCustomEditionActionClickListener(listener: ((Field) -> Unit)?) {
|
||||
this.mOnCustomEditionActionClickListener = listener
|
||||
@@ -80,9 +85,9 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
if (color != null) {
|
||||
backgroundColorView.background.colorFilter = BlendModeColorFilterCompat
|
||||
.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)
|
||||
backgroundColorView.visibility = View.VISIBLE
|
||||
backgroundColorView.visibility = VISIBLE
|
||||
} else {
|
||||
backgroundColorView.visibility = View.GONE
|
||||
backgroundColorView.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +108,9 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
if (color != null) {
|
||||
foregroundColorView.background.colorFilter = BlendModeColorFilterCompat
|
||||
.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)
|
||||
foregroundColorView.visibility = View.VISIBLE
|
||||
foregroundColorView.visibility = VISIBLE
|
||||
} else {
|
||||
foregroundColorView.visibility = View.GONE
|
||||
foregroundColorView.visibility = GONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,14 +118,25 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
headerContainerView.isVisible = true
|
||||
}
|
||||
|
||||
override fun buildLinearTextView(templateAttribute: TemplateAttribute,
|
||||
field: Field): TextEditFieldView? {
|
||||
override fun buildLinearTextView(
|
||||
templateAttribute: TemplateAttribute,
|
||||
field: Field
|
||||
): TextEditFieldView? {
|
||||
return context?.let {
|
||||
(if (TemplateField.isStandardPasswordName(context, templateAttribute.label))
|
||||
PasswordTextEditFieldView(it)
|
||||
else TextEditFieldView(it)).apply {
|
||||
// hiddenProtectedValue (mHideProtectedValue) don't work with TextInputLayout
|
||||
setProtection(field.protectedValue.isProtected)
|
||||
setProtection(
|
||||
protection = field.protectedValue.isProtected,
|
||||
isCurrentlyProtected = mUnprotectedFields.contains(field).not()
|
||||
) {
|
||||
mOnUnprotectClickListener?.invoke(field, this)
|
||||
}
|
||||
// Trick to bypass the onSaveInstanceState in rebuild child
|
||||
onSaveInstanceState = {
|
||||
saveUnprotectedFieldState(field, isCurrentlyProtected())
|
||||
}
|
||||
default = templateAttribute.default
|
||||
setMaxChars(templateAttribute.options.getNumberChars())
|
||||
setMaxLines(templateAttribute.options.getNumberLines())
|
||||
@@ -129,7 +145,7 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
textDirection = TEXT_DIRECTION_LTR
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO
|
||||
importantForAutofill = IMPORTANT_FOR_AUTOFILL_NO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +159,7 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
default = templateAttribute.default
|
||||
setActionClick(templateAttribute, field, this)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO
|
||||
importantForAutofill = IMPORTANT_FOR_AUTOFILL_NO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,7 +173,7 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
label = templateAttribute.alias
|
||||
?: TemplateField.getLocalizedName(context, field.name)
|
||||
val fieldValue = field.protectedValue.stringValue
|
||||
value = if (fieldValue.isEmpty()) templateAttribute.default else fieldValue
|
||||
value = fieldValue.ifEmpty { templateAttribute.default }
|
||||
// TODO edition and password generator at same time
|
||||
when (templateAttribute.action) {
|
||||
TemplateAttributeAction.NONE -> {
|
||||
@@ -187,7 +203,7 @@ class TemplateEditView @JvmOverloads constructor(context: Context,
|
||||
val value = field.protectedValue.toString().trim()
|
||||
type = dateInstantType
|
||||
activation = value.isNotEmpty()
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
type = dateInstantType
|
||||
activation = false
|
||||
}
|
||||
|
||||
@@ -25,12 +25,17 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
: TemplateAbstractView<TextFieldView, TextFieldView, DateTimeFieldView>
|
||||
(context, attrs, defStyle) {
|
||||
|
||||
private var mOnUnprotectClickListener: ((ProtectedFieldView) -> Unit)? = null
|
||||
fun setOnUnprotectClickListener(listener: ((ProtectedFieldView) -> Unit)?) {
|
||||
this.mOnUnprotectClickListener = listener
|
||||
}
|
||||
|
||||
private var mOnAskCopySafeClickListener: (() -> Unit)? = null
|
||||
fun setOnAskCopySafeClickListener(listener: (() -> Unit)? = null) {
|
||||
this.mOnAskCopySafeClickListener = listener
|
||||
}
|
||||
private var mOnCopyActionClickListener: ((Field) -> Unit)? = null
|
||||
fun setOnCopyActionClickListener(listener: ((Field) -> Unit)? = null) {
|
||||
private var mOnCopyActionClickListener: ((Field, ProtectedFieldView) -> Unit)? = null
|
||||
fun setOnCopyActionClickListener(listener: ((Field, ProtectedFieldView) -> Unit)? = null) {
|
||||
this.mOnCopyActionClickListener = listener
|
||||
}
|
||||
|
||||
@@ -58,7 +63,16 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
PasskeyTextFieldView(it)
|
||||
else TextFieldView(it)).apply {
|
||||
applyFontVisibility(mFontInVisibility)
|
||||
setProtection(field.protectedValue.isProtected, mHideProtectedValue)
|
||||
setProtection(
|
||||
protection = field.protectedValue.isProtected,
|
||||
isCurrentlyProtected = mUnprotectedFields.contains(field).not()
|
||||
) {
|
||||
mOnUnprotectClickListener?.invoke(this)
|
||||
}
|
||||
// Trick to bypass the onSaveInstanceState in rebuild child
|
||||
onSaveInstanceState = {
|
||||
saveUnprotectedFieldState(field, isCurrentlyProtected())
|
||||
}
|
||||
label = templateAttribute.alias
|
||||
?: TemplateField.getLocalizedName(context, field.name)
|
||||
setMaxChars(templateAttribute.options.getNumberChars())
|
||||
@@ -78,7 +92,15 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
setCopyButtonState(TextFieldView.ButtonState.ACTIVATE)
|
||||
setCopyButtonClickListener { label, value ->
|
||||
mOnCopyActionClickListener
|
||||
?.invoke(Field(label, ProtectedString(true, value)))
|
||||
?.invoke(
|
||||
Field(
|
||||
name = label,
|
||||
value = ProtectedString(
|
||||
enableProtection = true,
|
||||
string = value
|
||||
)
|
||||
), this
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setCopyButtonState(TextFieldView.ButtonState.GONE)
|
||||
@@ -89,7 +111,15 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
setCopyButtonState(TextFieldView.ButtonState.ACTIVATE)
|
||||
setCopyButtonClickListener { label, value ->
|
||||
mOnCopyActionClickListener
|
||||
?.invoke(Field(label, ProtectedString(false, value)))
|
||||
?.invoke(
|
||||
Field(
|
||||
name = label,
|
||||
value = ProtectedString(
|
||||
enableProtection = false,
|
||||
string = value
|
||||
)
|
||||
), this
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,7 +144,7 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
try {
|
||||
val value = field.protectedValue.toString().trim()
|
||||
activation = value.isNotEmpty()
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
activation = false
|
||||
}
|
||||
}
|
||||
@@ -177,9 +207,15 @@ class TemplateView @JvmOverloads constructor(context: Context,
|
||||
value = otpElement.tokenString
|
||||
setCopyButtonState(TextFieldView.ButtonState.ACTIVATE)
|
||||
setCopyButtonClickListener { _, _ ->
|
||||
mOnCopyActionClickListener?.invoke(Field(
|
||||
otpElement.type.name,
|
||||
ProtectedString(false, otpElement.token)))
|
||||
mOnCopyActionClickListener?.invoke(
|
||||
Field(
|
||||
name = otpElement.type.name,
|
||||
value = ProtectedString(
|
||||
enableProtection = false,
|
||||
string = otpElement.token
|
||||
)
|
||||
), this
|
||||
)
|
||||
}
|
||||
textDirection = TEXT_DIRECTION_LTR
|
||||
mLastOtpTokenView = this
|
||||
|
||||
@@ -6,12 +6,13 @@ import android.text.InputFilter
|
||||
import android.text.InputType
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.method.PasswordTransformationMethod
|
||||
import android.text.method.SingleLineTransformationMethod
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.appcompat.widget.AppCompatImageButton
|
||||
@@ -21,12 +22,11 @@ import androidx.core.view.isVisible
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||
|
||||
open class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyle: Int = 0)
|
||||
: RelativeLayout(context, attrs, defStyle), GenericTextFieldView {
|
||||
: ProtectedTextFieldView(context, attrs, defStyle) {
|
||||
|
||||
private var labelViewId = ViewCompat.generateViewId()
|
||||
private var valueViewId = ViewCompat.generateViewId()
|
||||
@@ -169,14 +169,29 @@ open class TextEditFieldView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
}
|
||||
|
||||
fun setProtection(protection: Boolean) {
|
||||
if (protection) {
|
||||
override fun setProtection(
|
||||
protection: Boolean,
|
||||
isCurrentlyProtected: Boolean,
|
||||
onUnprotectClickListener: OnClickListener?
|
||||
) {
|
||||
super.setProtection(protection, isCurrentlyProtected, onUnprotectClickListener)
|
||||
if (isProtected) {
|
||||
labelView.endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE
|
||||
val visibilityTag = if (PreferencesUtil.hideProtectedValue(context))
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
else
|
||||
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
valueView.inputType = valueView.inputType or visibilityTag
|
||||
// FIXME Called by itself during orientation change
|
||||
/*
|
||||
labelView.setEndIconOnClickListener {
|
||||
onUnprotectClickListener?.onClick(this@TextEditFieldView)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
override fun changeProtectedValueParameters() {
|
||||
if (isCurrentlyProtected()) {
|
||||
valueView.inputType = valueView.inputType or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
valueView.transformationMethod = PasswordTransformationMethod.getInstance()
|
||||
} else {
|
||||
valueView.inputType = valueView.inputType or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
valueView.transformationMethod = SingleLineTransformationMethod.getInstance()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.AppCompatImageButton
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
@@ -42,7 +41,7 @@ import com.kunzisoft.keepass.utils.AppUtil.openExternalApp
|
||||
open class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyle: Int = 0)
|
||||
: RelativeLayout(context, attrs, defStyle), GenericTextFieldView {
|
||||
: ProtectedTextFieldView(context, attrs, defStyle) {
|
||||
|
||||
protected var labelViewId = ViewCompat.generateViewId()
|
||||
private var valueViewId = ViewCompat.generateViewId()
|
||||
@@ -204,25 +203,29 @@ open class TextFieldView @JvmOverloads constructor(context: Context,
|
||||
}
|
||||
}
|
||||
|
||||
fun setProtection(protection: Boolean, hiddenProtectedValue: Boolean = false) {
|
||||
showButton.isVisible = protection
|
||||
showButton.isSelected = hiddenProtectedValue
|
||||
showButton.setOnClickListener {
|
||||
showButton.isSelected = !showButton.isSelected
|
||||
changeProtectedValueParameters()
|
||||
override fun setProtection(
|
||||
protection: Boolean,
|
||||
isCurrentlyProtected: Boolean,
|
||||
onUnprotectClickListener: OnClickListener?
|
||||
) {
|
||||
super.setProtection(protection, isCurrentlyProtected, onUnprotectClickListener)
|
||||
showButton.isVisible = isProtected
|
||||
if (isProtected) {
|
||||
showButton.setOnClickListener {
|
||||
onUnprotectClickListener?.onClick(this@TextFieldView)
|
||||
}
|
||||
}
|
||||
changeProtectedValueParameters()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
protected fun changeProtectedValueParameters() {
|
||||
override fun changeProtectedValueParameters() {
|
||||
valueView.apply {
|
||||
if (showButton.isVisible) {
|
||||
applyHiddenStyle(showButton.isSelected)
|
||||
applyHiddenStyle(isCurrentlyProtected())
|
||||
} else {
|
||||
linkify()
|
||||
}
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private fun linkify() {
|
||||
|
||||
@@ -238,15 +238,13 @@ fun View.updateLockPaddingStart() {
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.toastError(e: Throwable) {
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
if (e is LocalizedException)
|
||||
e.getLocalizedMessage(resources)
|
||||
else
|
||||
e.localizedMessage,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
fun Context.toastError(e: Throwable?) {
|
||||
val message = if (e is LocalizedException)
|
||||
e.getLocalizedMessage(resources)
|
||||
else e?.localizedMessage
|
||||
message?.let {
|
||||
Toast.makeText(applicationContext, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.showActionErrorIfNeeded(result: ActionRunnable.Result) {
|
||||
@@ -259,6 +257,15 @@ fun Context.showActionErrorIfNeeded(result: ActionRunnable.Result) {
|
||||
}
|
||||
}
|
||||
|
||||
fun CoordinatorLayout.showError(error: Throwable?) {
|
||||
val message = if (error is LocalizedException) {
|
||||
error.getLocalizedMessage(resources) ?: error.message
|
||||
} else error?.message
|
||||
message?.let {
|
||||
Snackbar.make(this, message, Snackbar.LENGTH_LONG).asError().show()
|
||||
}
|
||||
}
|
||||
|
||||
fun CoordinatorLayout.showActionErrorIfNeeded(result: ActionRunnable.Result) {
|
||||
if (!result.isSuccess) {
|
||||
result.exception?.getLocalizedMessage(resources)?.let { errorMessage ->
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.kunzisoft.keepass.model.RegisterInfo
|
||||
import com.kunzisoft.keepass.model.StreamDirection
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.view.ProtectedFieldView
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
@@ -37,7 +38,6 @@ class EntryEditViewModel: NodeEditViewModel() {
|
||||
|
||||
// To show dialog only one time
|
||||
var backPressedAlreadyApproved = false
|
||||
var warningOverwriteDataAlreadyApproved = false
|
||||
|
||||
// Useful to not relaunch a current action
|
||||
private var actionLocked: Boolean = false
|
||||
@@ -81,8 +81,8 @@ class EntryEditViewModel: NodeEditViewModel() {
|
||||
val onBinaryPreviewLoaded : LiveData<AttachmentPosition> get() = _onBinaryPreviewLoaded
|
||||
private val _onBinaryPreviewLoaded = SingleLiveEvent<AttachmentPosition>()
|
||||
|
||||
private val mUiState = MutableStateFlow<UIState>(UIState.Loading)
|
||||
val uiState: StateFlow<UIState> = mUiState
|
||||
private val mEntryEditState = MutableStateFlow<EntryEditState>(EntryEditState.Loading)
|
||||
val entryEditState: StateFlow<EntryEditState> = mEntryEditState
|
||||
|
||||
fun loadTemplateEntry(database: ContextualDatabase?) {
|
||||
loadTemplateEntry(database, mEntryId, mParentId, mRegisterInfo)
|
||||
@@ -125,7 +125,7 @@ class EntryEditViewModel: NodeEditViewModel() {
|
||||
mEntryId = null
|
||||
_templatesEntry.value = templatesEntry
|
||||
if (templatesEntry?.overwrittenData == true) {
|
||||
mUiState.value = UIState.ShowOverwriteMessage
|
||||
mEntryEditState.value = EntryEditState.ShowOverwriteMessage
|
||||
}
|
||||
}
|
||||
).execute()
|
||||
@@ -293,6 +293,10 @@ class EntryEditViewModel: NodeEditViewModel() {
|
||||
_onPasswordSelected.value = passwordField
|
||||
}
|
||||
|
||||
fun requestUnprotectField(fieldView: ProtectedFieldView) {
|
||||
mEntryEditState.value = EntryEditState.RequestUnprotectField(fieldView)
|
||||
}
|
||||
|
||||
fun requestCustomFieldEdition(customField: Field) {
|
||||
_requestCustomFieldEdition.value = customField
|
||||
}
|
||||
@@ -348,6 +352,10 @@ class EntryEditViewModel: NodeEditViewModel() {
|
||||
_onBinaryPreviewLoaded.value = AttachmentPosition(entryAttachmentState, viewPosition)
|
||||
}
|
||||
|
||||
fun actionPerformed() {
|
||||
mEntryEditState.value = EntryEditState.Loading
|
||||
}
|
||||
|
||||
data class TemplatesEntry(
|
||||
val isTemplate: Boolean,
|
||||
val templates: List<Template>,
|
||||
@@ -362,9 +370,12 @@ class EntryEditViewModel: NodeEditViewModel() {
|
||||
data class AttachmentUpload(val attachmentToUploadUri: Uri, val attachment: Attachment)
|
||||
data class AttachmentPosition(val entryAttachmentState: EntryAttachmentState, val viewPosition: Float)
|
||||
|
||||
sealed class UIState {
|
||||
object Loading: UIState()
|
||||
object ShowOverwriteMessage: UIState()
|
||||
sealed class EntryEditState {
|
||||
object Loading: EntryEditState()
|
||||
object ShowOverwriteMessage: EntryEditState()
|
||||
data class RequestUnprotectField(
|
||||
val protectedFieldView: ProtectedFieldView
|
||||
): EntryEditState()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -19,25 +19,43 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
import com.kunzisoft.keepass.database.element.Attachment
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||
import com.kunzisoft.keepass.database.element.template.Template
|
||||
import com.kunzisoft.keepass.database.element.template.TemplateField
|
||||
import com.kunzisoft.keepass.database.helper.getLocalizedName
|
||||
import com.kunzisoft.keepass.model.EntryAttachmentState
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
import com.kunzisoft.keepass.timeout.ClipboardHelper
|
||||
import com.kunzisoft.keepass.utils.IOActionTask
|
||||
import com.kunzisoft.keepass.view.ProtectedFieldView
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
|
||||
class EntryViewModel: ViewModel() {
|
||||
class EntryViewModel(application: Application): AndroidViewModel(application) {
|
||||
|
||||
private var mMainEntryId: NodeId<UUID>? = null
|
||||
private var mHistoryPosition: Int = -1
|
||||
var mainEntryId: NodeId<UUID>? = null
|
||||
private set
|
||||
var entryInfo: EntryInfo? = null
|
||||
private set
|
||||
var historyPosition: Int = -1
|
||||
private set
|
||||
var entryIsHistory: Boolean = false
|
||||
private set
|
||||
var entryLoaded = false
|
||||
private set
|
||||
|
||||
private var mClipboardHelper: ClipboardHelper = ClipboardHelper(application)
|
||||
|
||||
val entryInfoHistory : LiveData<EntryInfoHistory?> get() = _entryInfoHistory
|
||||
private val _entryInfoHistory = MutableLiveData<EntryInfoHistory?>()
|
||||
@@ -59,13 +77,16 @@ class EntryViewModel: ViewModel() {
|
||||
val historySelected : LiveData<EntryHistory> get() = _historySelected
|
||||
private val _historySelected = SingleLiveEvent<EntryHistory>()
|
||||
|
||||
private val mEntryState = MutableStateFlow<EntryState>(EntryState.Loading)
|
||||
val entryState: StateFlow<EntryState> = mEntryState
|
||||
|
||||
fun loadDatabase(database: ContextualDatabase?) {
|
||||
loadEntry(database, mMainEntryId, mHistoryPosition)
|
||||
loadEntry(database, mainEntryId, historyPosition)
|
||||
}
|
||||
|
||||
fun loadEntry(database: ContextualDatabase?, mainEntryId: NodeId<UUID>?, historyPosition: Int = -1) {
|
||||
this.mMainEntryId = mainEntryId
|
||||
this.mHistoryPosition = historyPosition
|
||||
this.mainEntryId = mainEntryId
|
||||
this.historyPosition = historyPosition
|
||||
|
||||
if (database != null && mainEntryId != null) {
|
||||
IOActionTask(
|
||||
@@ -104,6 +125,13 @@ class EntryViewModel: ViewModel() {
|
||||
}
|
||||
},
|
||||
{ entryInfoHistory ->
|
||||
if (entryInfoHistory != null) {
|
||||
this.mainEntryId = entryInfoHistory.mainEntryId
|
||||
this.entryInfo = entryInfoHistory.entryInfo
|
||||
this.historyPosition = historyPosition
|
||||
this.entryIsHistory = historyPosition > -1
|
||||
this.entryLoaded = true
|
||||
}
|
||||
_entryInfoHistory.value = entryInfoHistory
|
||||
_entryHistory.value = entryInfoHistory?.entryHistory
|
||||
}
|
||||
@@ -111,6 +139,18 @@ class EntryViewModel: ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun requestUnprotectField(fieldView: ProtectedFieldView) {
|
||||
mEntryState.value = EntryState.RequestUnprotectField(fieldView)
|
||||
}
|
||||
|
||||
fun requestCopyField(field: Field, fieldView: ProtectedFieldView) {
|
||||
// Only request the User Verification if the field is protected and not shown
|
||||
if (field.protectedValue.isProtected && fieldView.isCurrentlyProtected())
|
||||
mEntryState.value = EntryState.RequestCopyProtectedField(field)
|
||||
else
|
||||
copyToClipboard(field)
|
||||
}
|
||||
|
||||
fun onOtpElementUpdated(optElement: OtpElement?) {
|
||||
_onOtpElementUpdated.value = optElement
|
||||
}
|
||||
@@ -131,6 +171,22 @@ class EntryViewModel: ViewModel() {
|
||||
_sectionSelected.value = section
|
||||
}
|
||||
|
||||
fun copyToClipboard(field: Field) {
|
||||
mClipboardHelper.timeoutCopyToClipboard(
|
||||
TemplateField.getLocalizedName(getApplication(), field.name),
|
||||
field.protectedValue.stringValue,
|
||||
field.protectedValue.isProtected
|
||||
)
|
||||
}
|
||||
|
||||
fun copyToClipboard(text: String) {
|
||||
mClipboardHelper.timeoutCopyToClipboard(text, text)
|
||||
}
|
||||
|
||||
fun actionPerformed() {
|
||||
mEntryState.value = EntryState.Loading
|
||||
}
|
||||
|
||||
data class EntryInfoHistory(var mainEntryId: NodeId<UUID>,
|
||||
var historyPosition: Int,
|
||||
val template: Template,
|
||||
@@ -152,6 +208,16 @@ class EntryViewModel: ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
sealed class EntryState {
|
||||
object Loading: EntryState()
|
||||
data class RequestUnprotectField(
|
||||
val protectedFieldView: ProtectedFieldView
|
||||
): EntryState()
|
||||
data class RequestCopyProtectedField(
|
||||
val field: Field
|
||||
): EntryState()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = EntryViewModel::class.java.name
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.kunzisoft.keepass.viewmodels
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.kunzisoft.keepass.database.MainCredential
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* ViewModel for the Main Credential Dialog
|
||||
* Easily retrieves main credential from the database identified by its URI
|
||||
*/
|
||||
class MainCredentialViewModel: ViewModel() {
|
||||
|
||||
private val mUiState = MutableStateFlow<UIState>(UIState.Loading)
|
||||
val uiState: StateFlow<UIState> = mUiState
|
||||
|
||||
fun validateMainCredential(
|
||||
databaseUri: Uri,
|
||||
mainCredential: MainCredential
|
||||
) {
|
||||
mUiState.value = UIState.OnMainCredentialEntered(databaseUri, mainCredential)
|
||||
}
|
||||
|
||||
fun cancelMainCredential(
|
||||
databaseUri: Uri?,
|
||||
error: Throwable? = null
|
||||
) {
|
||||
mUiState.value = UIState.OnMainCredentialCanceled(databaseUri, error)
|
||||
}
|
||||
|
||||
fun onActionReceived() {
|
||||
mUiState.value = UIState.Loading
|
||||
}
|
||||
|
||||
sealed class UIState {
|
||||
object Loading: UIState()
|
||||
data class OnMainCredentialEntered(
|
||||
val databaseUri: Uri,
|
||||
val mainCredential: MainCredential
|
||||
): UIState()
|
||||
data class OnMainCredentialCanceled(
|
||||
val databaseUri: Uri?,
|
||||
val error: Throwable?
|
||||
): UIState()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.kunzisoft.keepass.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class SettingsViewModel(application: Application): AndroidViewModel(application) {
|
||||
|
||||
private val mSettingsState = MutableStateFlow<SettingsState>(SettingsState.Wait)
|
||||
val settingsState: StateFlow<SettingsState> = mSettingsState
|
||||
|
||||
|
||||
var dialogFragment: DialogFragment? = null
|
||||
|
||||
fun showError(error: Throwable?) {
|
||||
mSettingsState.value = SettingsState.ShowError(error)
|
||||
}
|
||||
|
||||
fun errorShown() {
|
||||
mSettingsState.value = SettingsState.Wait
|
||||
}
|
||||
|
||||
sealed class SettingsState {
|
||||
object Wait: SettingsState()
|
||||
data class ShowError(
|
||||
val error: Throwable? = null
|
||||
): SettingsState()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.kunzisoft.keepass.viewmodels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.kunzisoft.keepass.credentialprovider.UserVerificationData
|
||||
import com.kunzisoft.keepass.database.element.MasterCredential.CREATOR.getCheckKey
|
||||
import com.kunzisoft.keepass.database.exception.InvalidCredentialsDatabaseException
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* ViewModel for the User Verification
|
||||
*/
|
||||
class UserVerificationViewModel: ViewModel() {
|
||||
|
||||
private val mUVState = MutableStateFlow<UVState>(UVState.Loading)
|
||||
val userVerificationState: StateFlow<UVState> = mUVState
|
||||
|
||||
var dataToVerify: UserVerificationData? = null
|
||||
|
||||
fun checkMainCredential(checkString: String) {
|
||||
// Check the password part
|
||||
val data = dataToVerify
|
||||
if (data?.database?.checkKey(getCheckKey(checkString)) == true)
|
||||
onUserVerificationSucceeded(data)
|
||||
else {
|
||||
onUserVerificationFailed(dataToVerify, InvalidCredentialsDatabaseException())
|
||||
}
|
||||
dataToVerify = null
|
||||
}
|
||||
|
||||
fun onUserVerificationSucceeded(dataToVerify: UserVerificationData) {
|
||||
mUVState.value = UVState.OnUserVerificationSucceeded(dataToVerify)
|
||||
}
|
||||
|
||||
fun onUserVerificationFailed(
|
||||
dataToVerify: UserVerificationData? = null,
|
||||
error: Throwable? = null
|
||||
) {
|
||||
this.dataToVerify = dataToVerify
|
||||
mUVState.value = UVState.OnUserVerificationCanceled(dataToVerify, error)
|
||||
}
|
||||
|
||||
fun onUserVerificationReceived() {
|
||||
mUVState.value = UVState.Loading
|
||||
}
|
||||
|
||||
sealed class UVState {
|
||||
object Loading: UVState()
|
||||
data class OnUserVerificationSucceeded(
|
||||
val dataToVerify: UserVerificationData
|
||||
): UVState()
|
||||
data class OnUserVerificationCanceled(
|
||||
val dataToVerify: UserVerificationData?,
|
||||
val error: Throwable?
|
||||
): UVState()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M11,4C9.95,4 9.063,4.363 8.338,5.088C7.613,5.813 7.25,6.7 7.25,7.75C7.25,8.8 7.613,9.687 8.338,10.412C9.063,11.137 9.95,11.5 11,11.5C12.05,11.5 12.937,11.137 13.662,10.412C14.387,9.687 14.75,8.8 14.75,7.75C14.75,6.7 14.387,5.813 13.662,5.088C12.937,4.363 12.05,4 11,4zM11,13.5C10.567,13.5 10.147,13.521 9.738,13.563C9.33,13.604 8.908,13.667 8.475,13.75C8.47,13.754 8.049,13.845 7.912,13.875C6.887,14.125 5.816,14.5 4.699,15C4.199,15.233 3.791,15.575 3.475,16.025C3.158,16.475 3,17.017 3,17.65L3,20L6,20L13.682,20C13.429,19.394 13.287,18.729 13.287,18.031C13.287,16.501 13.971,15.144 15.033,14.205C14.724,14.11 14.389,13.949 14.088,13.875C14.08,13.877 13.525,13.75 13.525,13.75C13.301,13.707 13.089,13.684 12.871,13.652C12.721,13.63 12.57,13.603 12.42,13.586C12.368,13.58 12.313,13.568 12.262,13.563C11.853,13.521 11.433,13.5 11,13.5zM18.414,14.445C16.433,14.445 14.826,16.05 14.826,18.031C14.826,20.012 16.433,21.619 18.414,21.619C20.395,21.619 22,20.012 22,18.031C22,16.05 20.395,14.445 18.414,14.445zM19.848,16.314C19.956,16.314 20.064,16.355 20.146,16.438L20.443,16.736C20.608,16.9 20.607,17.168 20.443,17.332L18.145,19.633C17.98,19.797 17.711,19.797 17.547,19.633L16.391,18.475C16.226,18.31 16.226,18.043 16.391,17.879L16.689,17.58C16.854,17.416 17.121,17.416 17.285,17.58L17.846,18.139L19.549,16.438C19.631,16.355 19.739,16.314 19.848,16.314z"
|
||||
android:fillColor="#7D7D7D"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2025 Jeremy Jamet / Kunzisoft.
|
||||
|
||||
This file is part of KeePassDX.
|
||||
|
||||
KeePassDX is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
KeePassDX is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:padding="@dimen/default_margin"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:importantForAutofill="noExcludeDescendants"
|
||||
tools:targetApi="o">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" >
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/user_verification_information"
|
||||
android:text="@string/user_verification_required_title"
|
||||
style="@style/KeepassDXStyle.Title"/>
|
||||
<ImageView
|
||||
android:id="@+id/user_verification_information"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:src="@drawable/ic_info_white_24dp"
|
||||
style="@style/KeepassDXStyle.ImageButton.Simple"
|
||||
android:contentDescription="@string/content_description_user_verification_information"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_verification_required_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/card_view_margin_horizontal"
|
||||
android:layout_marginLeft="@dimen/card_view_margin_horizontal"
|
||||
android:layout_marginEnd="@dimen/card_view_margin_horizontal"
|
||||
android:layout_marginRight="@dimen/card_view_margin_horizontal"
|
||||
android:text="@string/user_verification_database_credential"
|
||||
android:textColor="?attr/colorSecondary"/>
|
||||
|
||||
<!-- Password -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/setup_check_password_input_layout"
|
||||
android:layout_margin="@dimen/card_view_margin_horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:endIconMode="password_toggle"
|
||||
app:endIconTint="?attr/colorSecondary">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/setup_check_password_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
android:focusedByDefault="true"
|
||||
android:inputType="textPassword"
|
||||
android:importantForAccessibility="no"
|
||||
android:importantForAutofill="no"
|
||||
android:hint="@string/first_chars" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -75,8 +75,7 @@
|
||||
<com.kunzisoft.keepass.view.PasswordEditView
|
||||
android:id="@+id/password_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:passwordVisible="false"/>
|
||||
android:layout_height="wrap_content"/>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/password_repeat_input_layout"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
1
app/src/main/res/resources.properties
Normal file
1
app/src/main/res/resources.properties
Normal file
@@ -0,0 +1 @@
|
||||
unqualifiedResLocale=en-US
|
||||
@@ -61,7 +61,6 @@
|
||||
<string name="list_size_summary">حجم النص في قائمة العناصر</string>
|
||||
<string name="loading_database">يحمل قاعدة البيانات…</string>
|
||||
<string name="lowercase">حروف صغيرة</string>
|
||||
<string name="hide_password_summary">أخفِ كلمات السر (***) افتراضيًا</string>
|
||||
<string name="about">عن التطبيق</string>
|
||||
<string name="menu_change_key_settings">تغيير المفتاح الرئيسي</string>
|
||||
<string name="settings">الإعدادات</string>
|
||||
@@ -143,13 +142,11 @@
|
||||
<string name="list_entries_show_username_summary">يعرض اسماء المستخدمين في قوائم المدخلات</string>
|
||||
<string name="hint_generated_password">كلمة السر مولّدة</string>
|
||||
<string name="hint_keyfile">ملف المفتاح</string>
|
||||
<string name="hide_password_title">أخفِ كلمات السر</string>
|
||||
<string name="copy_field">نُسخة من %1$s</string>
|
||||
<string name="menu_copy">نسخ</string>
|
||||
<string name="menu_move">نقل</string>
|
||||
<string name="menu_paste">لصق</string>
|
||||
<string name="menu_cancel">ألغِ</string>
|
||||
<string name="menu_hide_password">أخفِ كلمة السر</string>
|
||||
<string name="menu_showpass">أظهر كلمة السر</string>
|
||||
<string name="menu_url">الانتقال الى الرابط</string>
|
||||
<string name="menu_file_selection_read_only">محمي من التعديل</string>
|
||||
|
||||
@@ -142,7 +142,6 @@
|
||||
<string name="menu_paste">Mubadilə buferindən əlavə et</string>
|
||||
<string name="menu_delete">Sil</string>
|
||||
<string name="menu_cancel">Ləğv et</string>
|
||||
<string name="menu_hide_password">Şifrəni gizlət</string>
|
||||
<string name="menu_lock">Məlumat bazasını kilidlə</string>
|
||||
<string name="menu_save_database">Məlumatları yadda saxla</string>
|
||||
<string name="menu_merge_database">Məlumatları birləşdir</string>
|
||||
@@ -448,8 +447,6 @@
|
||||
<string name="invalid_db_sig">Məlumat bazasının formatını tanımaq mümkün olmadı.</string>
|
||||
<string name="keyfile_is_empty">Açar faylı boşdur.</string>
|
||||
<string name="length">Uzunluq</string>
|
||||
<string name="hide_password_title">Şifrələri gizlət</string>
|
||||
<string name="hide_password_summary">Şifrələri standart olaraq (***) ilə maskala</string>
|
||||
<string name="colorize_password_title">Şifrələri rəngləndir</string>
|
||||
<string name="colorize_password_summary">Şifrə hərflərini (simvollarını) növə görə rəngləndir</string>
|
||||
<string name="list_entries_show_username_title">İstifadəçi adlarını göstər</string>
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
<string name="menu_open">Otvori</string>
|
||||
<string name="menu_save_database">Sačuvaj podatake</string>
|
||||
<string name="menu_lock">Zaključaj bazu podataka</string>
|
||||
<string name="menu_hide_password">Sakrij lozinku</string>
|
||||
<string name="menu_cancel">Otkaži</string>
|
||||
<string name="menu_delete">Izbriši</string>
|
||||
<string name="menu_paste">Nalepi</string>
|
||||
@@ -47,8 +46,6 @@
|
||||
<string name="copy_field">Kopija od %1$s</string>
|
||||
<string name="menu_change_key_settings">Promeni glavni ključ</string>
|
||||
<string name="about">O aplikaciji</string>
|
||||
<string name="hide_password_summary">Podrazumevaj maskiranje lozinki sa (***)</string>
|
||||
<string name="hide_password_title">Sakrij lozinke</string>
|
||||
<string name="lowercase">Mala slova</string>
|
||||
<string name="loading_database">Učitavanje baze podataka…</string>
|
||||
<string name="creating_database">Kreiranje baze podataka…</string>
|
||||
|
||||
@@ -216,8 +216,6 @@
|
||||
<string name="keyfile_is_empty">Файл ключа пусты.</string>
|
||||
<string name="length">Даўжыня</string>
|
||||
<string name="nodes">Вузлы</string>
|
||||
<string name="hide_password_title">Схаваць паролі</string>
|
||||
<string name="hide_password_summary">Маскіраваць паролі (***) па змаўчанні</string>
|
||||
<string name="colorize_password_title">Размаляваць паролі</string>
|
||||
<string name="colorize_password_summary">Размаляваць сімвалы пароля па тыпу</string>
|
||||
<string name="list_entries_show_username_title">Паказаць імёны карыстальнікаў</string>
|
||||
@@ -258,7 +256,6 @@
|
||||
<string name="menu_paste">Уставіць</string>
|
||||
<string name="menu_delete">Выдаліць</string>
|
||||
<string name="menu_cancel">Адмена</string>
|
||||
<string name="menu_hide_password">Схаваць пароль</string>
|
||||
<string name="menu_lock">Заблакаваць базу дадзеных</string>
|
||||
<string name="menu_save_database">Захаваць дадзеныя</string>
|
||||
<string name="menu_merge_database">Аб\'яднаць дадзеныя</string>
|
||||
|
||||
@@ -71,10 +71,8 @@
|
||||
<string name="unlock">Отключване</string>
|
||||
<string name="unavailable_feature_hardware">Необходимият хардуер не може да бъде намерен.</string>
|
||||
<string name="hardware_key">Хардуерен ключ</string>
|
||||
<string name="hide_password_summary">Скриване на паролите (***) по подразбиране</string>
|
||||
<string name="select_database_file">Отключване на хранилище</string>
|
||||
<string name="content_description_hardware_key_checkbox">Отметка на поле с хардуерен ключ</string>
|
||||
<string name="hide_password_title">Скриване на пароли</string>
|
||||
<string name="hint_pass">Парола</string>
|
||||
<string name="education_select_database_title">Отворете съществуващо хранилище</string>
|
||||
<string name="content_description_keyfile_checkbox">Отметка на поле за файл с ключ</string>
|
||||
@@ -157,7 +155,6 @@
|
||||
<string name="template">Шаблон</string>
|
||||
<string name="menu_move">Преместване</string>
|
||||
<string name="menu_cancel">Отказ</string>
|
||||
<string name="menu_hide_password">Скриване на парола</string>
|
||||
<string name="auto_focus_search_summary">Търсене при отключване на хранилище</string>
|
||||
<string name="saving_database">Запазване на хранилището…</string>
|
||||
<string name="command_execution">Изпълнение на команда…</string>
|
||||
@@ -690,11 +687,11 @@
|
||||
<string name="passkeys_preference_title">Настройки на ключове за достъп</string>
|
||||
<string name="passkeys_close_database_title">Затваряне на хранилище</string>
|
||||
<string name="passkeys_close_database_summary">Затваряне на хранилището след избор на ключ за достъп</string>
|
||||
<string name="passkeys_privileged_apps_explanation">ВНИМАНИЕ: Привилегированото приложение работи като шлюз, който получава източника на удостоверяването. За да избегнете проблеми със сигурността се уверете в неговата автентичност.</string>
|
||||
<string name="passkeys_privileged_apps_title">Привилегировани приложения</string>
|
||||
<string name="passkeys_privileged_apps_summary">Управление на мрежови четци в потребителския списък с привилегировани приложения</string>
|
||||
<string name="passkeys_privileged_apps_explanation">ВНИМАНИЕ: Приложенията с допълнителни права играят ролята на шлюз, от който се получава произхода на удостоверяването. За да избегнете проблеми със сигурността се уверете в неговата автентичност.</string>
|
||||
<string name="passkeys_privileged_apps_title">Приложения с допълнителни права</string>
|
||||
<string name="passkeys_privileged_apps_summary">Управление на мрежови четци в потребителския списък на приложения с допълнителни права</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">Неразпознато приложение</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">Приложението „%1$s“ опитва да извърши действия с ключ за достъп .\n\nДа бъде ли добавено в списъка с привилегировани приложения?</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">Приложението „%1$s“ опитва да извърши действия с ключ за достъп .\n\nДа бъде ли добавено в списъка на приложения с допълнителни права?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">Липсващ подпис</string>
|
||||
<string name="passkeys_missing_signature_app_ask_message">Приложението „%1$s“ не е разпознато, но се опитва да извърши удостоверяване с ключ за достъп.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">Добавяне на подпис към запис на ключ за достъп?</string>
|
||||
@@ -721,5 +718,5 @@
|
||||
<string name="passkey_backup_state">Състояние на резервно копие на ключа за достъп</string>
|
||||
<string name="error_passkey_result">Грешка при връщане на ключ за достъп</string>
|
||||
<string name="passkey_relying_party">Доверяваща страна на ключа за достъп</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">ВНИМАНИЕ: Ключът за достъп е създаден от друг клиент или подписът е премахнат. За да избегнете проблеми със сигурността се уверете, че приложението, което удостоверявате е част от същата услуга и е автентично.\nАко приложението е мрежов четец не добавяйте подписа му към записа, а в настройките го добавете в списъка с привилегировани приложения.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">ВНИМАНИЕ: Ключът за достъп е създаден от друг клиент или подписът е премахнат. За да избегнете проблеми със сигурността се уверете, че приложението, което удостоверявате е част от същата услуга и е автентично.\nАко приложението е мрежов четец не добавяйте подписа му към записа, а в настройките го добавете в списъка на приложенията с допълнителни права.</string>
|
||||
</resources>
|
||||
|
||||
@@ -182,7 +182,6 @@
|
||||
<string name="invalid_db_same_uuid">একই UUID সহ %1$s %2$s ইতিমধ্যেই বিদ্যমান।</string>
|
||||
<string name="passphrase">পাসফ্রেজ</string>
|
||||
<string name="keyfile_is_empty">কী ফাইলটি খালি।</string>
|
||||
<string name="hide_password_title">পাসওয়ার্ড লুকান</string>
|
||||
<string name="list_size_summary">উপাদান তালিকায় পাঠ্যের আকার</string>
|
||||
<string name="creating_database">ডাটাবেস তৈরি করা হচ্ছে…</string>
|
||||
<string name="loading_database">ডাটাবেস লোড হচ্ছে…</string>
|
||||
@@ -316,7 +315,6 @@
|
||||
<string name="field_value">ক্ষেত্রের মান</string>
|
||||
<string name="corrupted_file">দূষিত ফাইল।</string>
|
||||
<string name="show_uuid_title">UUID দেখান</string>
|
||||
<string name="hide_password_summary">ডিফল্টরূপে মাস্ক পাসওয়ার্ড (***)</string>
|
||||
<string name="list_entries_show_username_title">ব্যবহারকারীর নাম দেখান</string>
|
||||
<string name="show_uuid_summary">একটি এন্ট্রি বা একটি গ্রুপের সাথে সংযুক্ত UUID প্রদর্শন করে</string>
|
||||
<string name="menu_reload_database">ডেটা পুনরায় লোড করুন</string>
|
||||
@@ -330,7 +328,6 @@
|
||||
<string name="menu_merge_database">ডেটা মার্জ করুন</string>
|
||||
<string name="menu_merge_from">থেকে মার্জ করুন…</string>
|
||||
<string name="menu_showpass">পাসওয়ার্ড দেখাও</string>
|
||||
<string name="menu_hide_password">পাসওয়ার্ড লুকান</string>
|
||||
<string name="menu_lock">ডাটাবেস লক করুন</string>
|
||||
<string name="menu_url">URL-এ যান</string>
|
||||
<string name="menu_empty_recycle_bin">রিসাইকেল বিন খালি করুন</string>
|
||||
|
||||
@@ -84,8 +84,6 @@
|
||||
<string name="list_size_summary">Mida del text a la llista de grups</string>
|
||||
<string name="loading_database">Carregant base de dades…</string>
|
||||
<string name="lowercase">Minúscules</string>
|
||||
<string name="hide_password_title">Emmascara contrasenya</string>
|
||||
<string name="hide_password_summary">Amaga les contrasenyes per defecte</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="menu_change_key_settings">Canvia Clau Mestra</string>
|
||||
<string name="settings">Paràmetres</string>
|
||||
@@ -93,7 +91,6 @@
|
||||
<string name="menu_delete">Esborra</string>
|
||||
<string name="menu_donate">Donar</string>
|
||||
<string name="menu_edit">Editar</string>
|
||||
<string name="menu_hide_password">Amaga contrasenya</string>
|
||||
<string name="menu_lock">Bloca la base de dades</string>
|
||||
<string name="menu_open">Obre</string>
|
||||
<string name="menu_search">Cerca</string>
|
||||
|
||||
@@ -90,8 +90,6 @@
|
||||
<string name="list_size_summary">Velikost textu v seznamu prvků</string>
|
||||
<string name="loading_database">Načítám databázi…</string>
|
||||
<string name="lowercase">Malá písmena</string>
|
||||
<string name="hide_password_title">Skrýt hesla</string>
|
||||
<string name="hide_password_summary">Ve výchozím stavu zobrazit (***) místo hesla</string>
|
||||
<string name="about">O aplikaci</string>
|
||||
<string name="menu_change_key_settings">Změnit hlavní klíč</string>
|
||||
<string name="settings">Nastavení</string>
|
||||
@@ -99,7 +97,6 @@
|
||||
<string name="menu_delete">Smazat</string>
|
||||
<string name="menu_donate">Přispět darem</string>
|
||||
<string name="menu_edit">Upravit</string>
|
||||
<string name="menu_hide_password">Skrýt heslo</string>
|
||||
<string name="menu_lock">Zamknout databázi</string>
|
||||
<string name="menu_open">Otevřít</string>
|
||||
<string name="menu_search">Hledat</string>
|
||||
|
||||
@@ -89,8 +89,6 @@
|
||||
<string name="list_size_summary">Tekststørrelse i elementlisten</string>
|
||||
<string name="loading_database">Indlæser database…</string>
|
||||
<string name="lowercase">Små bogstaver</string>
|
||||
<string name="hide_password_title">Skjul adgangskoder</string>
|
||||
<string name="hide_password_summary">Skjul adgangskoder (***) som standard</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="menu_change_key_settings">Skift hovednøgle</string>
|
||||
<string name="settings">Indstillinger</string>
|
||||
@@ -98,7 +96,6 @@
|
||||
<string name="menu_delete">Slet</string>
|
||||
<string name="menu_donate">Donér</string>
|
||||
<string name="menu_edit">Rediger</string>
|
||||
<string name="menu_hide_password">Skjul adgangskode</string>
|
||||
<string name="menu_lock">Lås database</string>
|
||||
<string name="menu_open">Åbn</string>
|
||||
<string name="menu_search">Søg</string>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
Translations from David Ramiro
|
||||
--><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<string name="contact">Kontakt</string>
|
||||
<string name="contribution">Beiträge</string>
|
||||
<string name="contribution">Beitrag</string>
|
||||
<string name="feedback">Feedback</string>
|
||||
<string name="homepage">Webseite</string>
|
||||
<string name="about_description">Android-Implementierung des Passwortmanagers KeePass.</string>
|
||||
@@ -99,8 +99,6 @@
|
||||
<string name="list_size_summary">Schriftgröße der Listenelemente</string>
|
||||
<string name="loading_database">Datenbank wird geladen …</string>
|
||||
<string name="lowercase">Kleinbuchstaben</string>
|
||||
<string name="hide_password_title">Passwörter verbergen</string>
|
||||
<string name="hide_password_summary">Passwörter mit (***) maskieren</string>
|
||||
<string name="about">Über</string>
|
||||
<string name="menu_change_key_settings">Hauptschlüssel ändern</string>
|
||||
<string name="settings">Einstellungen</string>
|
||||
@@ -108,7 +106,6 @@
|
||||
<string name="menu_delete">Löschen</string>
|
||||
<string name="menu_donate">Spenden</string>
|
||||
<string name="menu_edit">Bearbeiten</string>
|
||||
<string name="menu_hide_password">Passwort verbergen</string>
|
||||
<string name="menu_lock">Datenbank sperren</string>
|
||||
<string name="menu_open">Öffnen</string>
|
||||
<string name="menu_search">Suche</string>
|
||||
@@ -498,7 +495,7 @@
|
||||
<string name="keyboard_save_search_info_title">Geteilte Informationen speichern</string>
|
||||
<string name="warning_empty_recycle_bin">Alle Knoten unwiderruflich aus dem Papierkorb löschen\?</string>
|
||||
<string name="error_field_name_already_exists">Der Feldname existiert bereits.</string>
|
||||
<string name="device_unlock_prompt_store_credential_message">Du musst dich weiterhin an deinen Hauptschlüssel erinnern, wenn du die Geräteentsperrung verwendest.</string>
|
||||
<string name="device_unlock_prompt_store_credential_message">Falls die Geräteentsperrung verwendet wird, ist es immer noch notwendig, sich die Hauptzugangsdaten für den Tresor zu merken.</string>
|
||||
<string name="menu_keystore_remove_key">Schlüssel für Geräteentsperrung löschen</string>
|
||||
<string name="device_unlock_prompt_store_credential_title">Verknüpfung mit Geräteentsperrung</string>
|
||||
<string name="education_device_unlock_summary">Eigenes Passwort mit Biometrie- oder Geräteanmeldedaten verknüpfen, um die Datenbank schnell zu entsperren.</string>
|
||||
@@ -728,4 +725,21 @@
|
||||
<string name="passkeys_close_database_summary">Datenbank nach der Passwortauswahl schließen</string>
|
||||
<string name="credential_provider">Anmeldeinformationsanbieter</string>
|
||||
<string name="passkeys_explanation_summary">Passkeys für eine schnelle und sichere Anmeldung ohne Passwort konfigurieren</string>
|
||||
<string name="passkeys_privileged_apps_summary">Browser in der benutzerdefinierten Liste privilegierter Apps verwalten</string>
|
||||
<string name="passkeys_privileged_apps_explanation">WARNUNG: Eine privilegierte App fungiert als Gateway, um die Herkunft einer Authentifizierung abzurufen. Zur Vermeidung von Sicherheitsproblemen ist ihre Legitimität sicherzustellen.</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">%1$s versucht, eine Passkey-Aktion auszuführen.\n\nZur Liste der privilegierten Apps hinzufügen?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">WARNUNG: Der Passkey wurde von einem anderen Client erstellt oder die Signatur wurde gelöscht. Um Sicherheitsrisiken zu vermeiden, sollte die zu authentifizierende App zum selben Dienst gehören und legitimiert sein.\nWenn es sich bei der App um einen Browser handelt, dann die Signatur nicht zum Eintrag, sondern zur Liste der privilegierten Apps in den Einstellungen hinzufügen.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_message">%1$s wird nicht erkannt und versucht, sich mit einem vorhandenen Passkey zu authentifizieren.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">App-Signatur zum Passkey-Eintrag hinzufügen?</string>
|
||||
<string name="passkeys_auto_select_summary">Automatische Auswahl, wenn nur ein Eintrag vorhanden und die Datenbank geöffnet ist, und nur, wenn die anfragende App kompatibel ist</string>
|
||||
<string name="passkeys_backup_eligibility_summary">Bei der Erstellung festlegen, ob die Quelle für öffentliche Schlüssel-Anmeldeinformationen gesichert werden darf</string>
|
||||
<string name="passkeys_backup_state_summary">Anzeigen, dass Anmeldedaten gesichert und gegen den Verlust eines einzelnen Geräts geschützt sind</string>
|
||||
<string name="credential_provider_service_subtitle">Passkeys, Anbieter für das automatische Ausfüllen von Anmeldedaten</string>
|
||||
<string name="passkey_service_name">KeePassDX-Anmeldeungsdatenanbieter</string>
|
||||
<string name="passkey_locked_database_description">Zum Entsperren auswählen</string>
|
||||
<string name="passkey_private_key">Passkey Privater Schlüssel</string>
|
||||
<string name="passkey_credential_id">Passkey-Anmeldeinformation</string>
|
||||
<string name="error_passkey_result">Passkey kann nicht zurückgegeben werden</string>
|
||||
<string name="passkey_user_handle">Passkey-Benutzerkennung</string>
|
||||
<string name="passkey_relying_party">Passkey-Vertrauensstelle</string>
|
||||
</resources>
|
||||
|
||||
@@ -92,8 +92,6 @@
|
||||
<string name="list_size_summary">Μέγεθος κειμένου στη λίστα στοιχείων</string>
|
||||
<string name="loading_database">Φόρτωση βάσης δεδομένων…</string>
|
||||
<string name="lowercase">Μικρά</string>
|
||||
<string name="hide_password_title">Απόκρυψη κωδικών πρόσβασης</string>
|
||||
<string name="hide_password_summary">Μάσκα κωδικούς πρόσβασης (***) από προεπιλογή</string>
|
||||
<string name="about">Σχετικά με</string>
|
||||
<string name="menu_change_key_settings">Αλλαγή Κύριου Κλειδιού</string>
|
||||
<string name="settings">Ρυθμίσεις</string>
|
||||
@@ -101,7 +99,6 @@
|
||||
<string name="menu_delete">Διαγραφή</string>
|
||||
<string name="menu_donate">Δωρεά</string>
|
||||
<string name="menu_edit">Επεξεργασία</string>
|
||||
<string name="menu_hide_password">Απόκρυψη κωδικού</string>
|
||||
<string name="menu_lock">Κλείδωμα βάσης δεδομένων</string>
|
||||
<string name="menu_open">Άνοιγμα</string>
|
||||
<string name="menu_search">Αναζήτηση</string>
|
||||
|
||||
@@ -219,8 +219,6 @@
|
||||
<string name="invalid_algorithm">Wrong algorithm.</string>
|
||||
<string name="invalid_db_same_uuid">%1$s with the same UUID %2$s already exists.</string>
|
||||
<string name="keyfile_is_empty">The keyfile is empty.</string>
|
||||
<string name="hide_password_title">Hide passwords</string>
|
||||
<string name="list_entries_show_username_title">Show usernames</string>
|
||||
<string name="error_otp_period">Period must be between %1$d and %2$d seconds.</string>
|
||||
<string name="error_string_type">This text does not match the requested item.</string>
|
||||
<string name="error_registration_read_only">Saving a new item is not allowed in a read-only database.</string>
|
||||
@@ -231,7 +229,6 @@
|
||||
<string name="error_file_to_big">The file you are trying to upload is too big.</string>
|
||||
<string name="error_upload_file">An error occurred while uploading the file data.</string>
|
||||
<string name="error_location_unknown">Database location is unknown, database action cannot be performed.</string>
|
||||
<string name="hide_password_summary">Mask passwords (***) by default</string>
|
||||
<string name="list_entries_show_username_summary">Displays usernames in entry lists</string>
|
||||
<string name="list_groups_show_number_entries_title">Show number of entries</string>
|
||||
<string name="show_otp_token_summary">Displays OTP tokens in the list of entries</string>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<string name="menu_reload_database">Reŝargi datumbazon</string>
|
||||
<string name="menu_save_database">Konservi datumbazon</string>
|
||||
<string name="menu_lock">Ŝlosi datumbazon</string>
|
||||
<string name="menu_hide_password">Kaŝi pasvorton</string>
|
||||
<string name="menu_cancel">Nuligi</string>
|
||||
<string name="menu_delete">Forigi</string>
|
||||
<string name="menu_paste">Algui</string>
|
||||
@@ -56,8 +55,6 @@
|
||||
<string name="settings">Agordoj</string>
|
||||
<string name="copy_field">Kopio de %1$s</string>
|
||||
<string name="about">Pri</string>
|
||||
<string name="hide_password_summary">Kaŝi pasvortojn sub (***) defaŭlte</string>
|
||||
<string name="hide_password_title">Kaŝi pasvortojn</string>
|
||||
<string name="loading_database">Datumbaza ŝarĝado…</string>
|
||||
<string name="creating_database">Datumbaza kreado…</string>
|
||||
<string name="list_entries_show_username_summary">Vidigi uzantnomojn en elementaj listoj</string>
|
||||
|
||||
@@ -84,8 +84,6 @@
|
||||
<string name="list_size_summary">Tamaño del texto en la lista de elementos</string>
|
||||
<string name="loading_database">Cargando base de datos…</string>
|
||||
<string name="lowercase">Minúsculas</string>
|
||||
<string name="hide_password_title">Ocultar contraseñas</string>
|
||||
<string name="hide_password_summary">Oculta contraseñas (***) por defecto</string>
|
||||
<string name="about">Acerca de</string>
|
||||
<string name="menu_change_key_settings">Cambiar contraseña maestra</string>
|
||||
<string name="settings">Configuración</string>
|
||||
@@ -93,7 +91,6 @@
|
||||
<string name="menu_delete">Eliminar</string>
|
||||
<string name="menu_donate">Donar</string>
|
||||
<string name="menu_edit">Editar</string>
|
||||
<string name="menu_hide_password">Ocultar contraseña</string>
|
||||
<string name="menu_lock">Bloquear la base de datos</string>
|
||||
<string name="menu_open">Abrir</string>
|
||||
<string name="menu_search">Buscar</string>
|
||||
@@ -165,7 +162,7 @@
|
||||
<string name="warning_no_encryption_key">¿Continuar sin clave de cifrado\?</string>
|
||||
<string name="encrypted_value_stored">Contraseña cifrada almacenada</string>
|
||||
<string name="database_history">Historial</string>
|
||||
<string name="autofill_explanation_summary">Habilite el servicio para rellenar formularios fácilmente desde otras aplicaciones</string>
|
||||
<string name="autofill_explanation_summary">Configura el autocompletado para rellenar rápidamente formularios en otras aplicaciones</string>
|
||||
<string name="unavailable">No disponible</string>
|
||||
<string name="menu_appearance_settings">Apariencia</string>
|
||||
<string name="general">General</string>
|
||||
@@ -195,7 +192,7 @@
|
||||
<string name="assign_master_key">Asignar una clave maestra</string>
|
||||
<string name="create_keepass_file">Crear una nueva bóveda</string>
|
||||
<string name="recycle_bin_title">Uso de la papelera de reciclaje</string>
|
||||
<string name="recycle_bin_summary">Mueve los grupos y las entradas al grupo \"Papelera de reciclaje\" antes de eliminarlos</string>
|
||||
<string name="recycle_bin_summary">Mueve los grupos y los apuntes al grupo \"Papelera de reciclaje\" antes de eliminarlos</string>
|
||||
<string name="monospace_font_fields_enable_title">Tipografía del campo</string>
|
||||
<string name="monospace_font_fields_enable_summary">Cambia la tipografía usada en los campos para una mejor visibilidad del carácter</string>
|
||||
<string name="allow_copy_password_title">Portapapeles de confianza</string>
|
||||
@@ -256,7 +253,7 @@
|
||||
<string name="error_load_database">No se ha podido cargar la base de datos.</string>
|
||||
<string name="error_load_database_KDF_memory">No se ha podido cargar la clave. Intente reducir el \"Uso de memoria\" del KDF.</string>
|
||||
<string name="list_entries_show_username_title">Mostrar nombres de usuario</string>
|
||||
<string name="list_entries_show_username_summary">Muestra los nombres de usuario en las listas de entrada</string>
|
||||
<string name="list_entries_show_username_summary">Muestra los nombres de usuario en las listas de apuntes</string>
|
||||
<string name="menu_copy">Copiar</string>
|
||||
<string name="menu_move">Mover</string>
|
||||
<string name="menu_paste">Pegar</string>
|
||||
@@ -274,12 +271,12 @@
|
||||
<string name="keyboard_name">Magikeyboard</string>
|
||||
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
|
||||
<string name="keyboard_setting_label">Configuración de Magikeyboard</string>
|
||||
<string name="keyboard_entry_category">Entrada</string>
|
||||
<string name="keyboard_entry_category">Apunte</string>
|
||||
<string name="keyboard_entry_timeout_title">Tiempo límite</string>
|
||||
<string name="keyboard_entry_timeout_summary">Tiempo límite para vaciar la entrada del teclado</string>
|
||||
<string name="keyboard_entry_timeout_summary">Tiempo límite para vaciar el apunte del teclado</string>
|
||||
<string name="keyboard_notification_entry_title">Información sobre notificación</string>
|
||||
<string name="keyboard_notification_entry_summary">Muestra una notificación cuando esté disponible un apunte</string>
|
||||
<string name="keyboard_notification_entry_content_title_text">Entrada</string>
|
||||
<string name="keyboard_notification_entry_content_title_text">Apunte</string>
|
||||
<string name="keyboard_notification_entry_content_title">%1$s disponible en Magikeyboard</string>
|
||||
<string name="keyboard_notification_entry_content_text">%1$s</string>
|
||||
<string name="keyboard_notification_entry_clear_close_title">Vaciar al cerrar</string>
|
||||
@@ -291,11 +288,11 @@
|
||||
<string name="keyboard_key_sound_title">Sonar al pulsar las teclas</string>
|
||||
<string name="selection_mode">Modo de selección</string>
|
||||
<string name="do_not_kill_app">No cierre la aplicación…</string>
|
||||
<string name="lock_database_back_root_summary">Bloquear la base de datos cuando el usuario pulse el botón atrás en la pantalla inicial</string>
|
||||
<string name="lock_database_back_root_summary">Pulse \'Atrás\' para bloquear la base de datos si se encuentra en la pantalla raíz de la base de datos</string>
|
||||
<string name="clear_clipboard_notification_title">Vaciar al cerrar</string>
|
||||
<string name="clear_clipboard_notification_summary">Bloquea la base de datos cuando caduque la duración del portapapeles o se cierre la notificación tras empezar a utilizarla</string>
|
||||
<string name="recycle_bin">Papelera de reciclaje</string>
|
||||
<string name="keyboard_selection_entry_title">Selección de entrada</string>
|
||||
<string name="keyboard_selection_entry_title">Selección de apuntes</string>
|
||||
<string name="keyboard_selection_entry_summary">Al visualizar un apunte en KeePassDX, rellena Magikeyboard con ese apunte</string>
|
||||
<string name="delete_entered_password_title">Eliminar contraseña</string>
|
||||
<string name="delete_entered_password_summary">Elimina la contraseña introducida tras un intento de conexión a una base de datos</string>
|
||||
@@ -315,8 +312,8 @@
|
||||
<string name="entry_UUID">UUID</string>
|
||||
<string name="error_move_entry_here">No puede mover un apunte aquí.</string>
|
||||
<string name="error_copy_entry_here">No puede copiar un apunte aquí.</string>
|
||||
<string name="list_groups_show_number_entries_title">Mostrar número de entradas</string>
|
||||
<string name="list_groups_show_number_entries_summary">Muestra el número de entradas de un grupo</string>
|
||||
<string name="list_groups_show_number_entries_title">Mostrar número de apunte</string>
|
||||
<string name="list_groups_show_number_entries_summary">Muestra el número de apuntes de un grupo</string>
|
||||
<string name="content_description_background">Fondo</string>
|
||||
<string name="content_description_update_from_list">Actualizar</string>
|
||||
<string name="content_description_keyboard_close_fields">Cerrar campos</string>
|
||||
@@ -498,7 +495,7 @@
|
||||
<string name="keyboard_auto_go_action_title">Acción automática de la tecla</string>
|
||||
<string name="keyboard_save_search_info_summary">Intente guardar información compartida cuando realice una selección manual de apunte para utilizar más fácil en el futuro</string>
|
||||
<string name="keyboard_save_search_info_title">Guardar información compartida</string>
|
||||
<string name="show_uuid_summary">Muestra el UUID vinculado a una entrada o a un grupo</string>
|
||||
<string name="show_uuid_summary">Muestra el UUID vinculado a un apuntes o a un grupo</string>
|
||||
<string name="show_uuid_title">Mostrar UUID</string>
|
||||
<string name="error_rebuild_list">No se puede reconstruir correctamente la lista.</string>
|
||||
<string name="error_database_uri_null">No se puede recuperar la URI de la base de datos.</string>
|
||||
@@ -513,7 +510,7 @@
|
||||
<string name="warning_database_info_changed_options">Fusionar los datos, sobrescribir las modificaciones externas guardando la base de datos o recargarla con los últimos cambios.</string>
|
||||
<string name="warning_database_info_changed">La información contenida en su archivo de base de datos ha sido modificada fuera de la aplicación.</string>
|
||||
<string name="menu_reload_database">Recargar datos</string>
|
||||
<string name="error_otp_type">El tipo de OTP existente no es reconocido por este formulario, es posible que su validación ya no genere correctamente el código.</string>
|
||||
<string name="error_otp_type">El tipo de OTP existente no es reconocido por este formulario, y es posible que su validación ya no genere correctamente el token.</string>
|
||||
<string name="download_canceled">¡Cancelado!</string>
|
||||
<string name="error_duplicate_file">Los datos del archivo ya existen.</string>
|
||||
<string name="error_upload_file">Se ha producido un error al cargar los datos del archivo.</string>
|
||||
@@ -539,7 +536,7 @@
|
||||
<string name="error_word_reserved">Esta palabra está reservada y no se puede usar.</string>
|
||||
<string name="templates">Plantillas</string>
|
||||
<string name="templates_group_uuid_title">Grupo de plantillas</string>
|
||||
<string name="templates_group_enable_summary">Utilice plantillas dinámicas para completar los campos de una entrada</string>
|
||||
<string name="templates_group_enable_summary">Utilice plantillas dinámicas para completar los campos de un apunte</string>
|
||||
<string name="templates_group_enable_title">Uso de plantillas</string>
|
||||
<string name="version">Versión</string>
|
||||
<string name="template">Plantilla</string>
|
||||
@@ -571,12 +568,12 @@
|
||||
<string name="ssid">SSID</string>
|
||||
<string name="personal_identification_number">PIN</string>
|
||||
<string name="card_verification_value">CVV</string>
|
||||
<string name="show_otp_token_summary">Muestra los códigos OTP en la lista de entradas</string>
|
||||
<string name="show_otp_token_summary">Muestra los códigos OTP en la lista de apuntes</string>
|
||||
<string name="show_otp_token_title">Mostrar código OTP</string>
|
||||
<string name="menu_external_icon">Icono externo</string>
|
||||
<string name="autofill_manual_selection_summary">Muestra la opción para permitir al usuario seleccionar la entrada de la base de datos</string>
|
||||
<string name="autofill_manual_selection_summary">Muestra la opción para permitir al usuario seleccionar el apunte de la base de datos</string>
|
||||
<string name="autofill_manual_selection_title">Selección manual</string>
|
||||
<string name="autofill_select_entry">Seleccionar entrada…</string>
|
||||
<string name="autofill_select_entry">Seleccionar apunte…</string>
|
||||
<string name="hint_icon_name">Nombre del icono</string>
|
||||
<string name="warning_exact_alarm">No ha permitido que la app use una alarma exacta. Como resultado, las funciones que requieren un temporizador no se harán con una hora exacta.</string>
|
||||
<string name="permission">Permiso</string>
|
||||
@@ -587,7 +584,7 @@
|
||||
<string name="warning_database_info_reloaded">La recarga de la base de datos borrará los datos modificados localmente.</string>
|
||||
<string name="warning_keyfile_integrity">El hash del archivo no está garantizado porque Android puede cambiar sus datos sobre la marcha. Cambia la extensión del archivo a .bin para una integridad correcta.</string>
|
||||
<string name="enable_keep_screen_on_title">Mantener pantalla encendida</string>
|
||||
<string name="enable_keep_screen_on_summary">Mantiene la pantalla encendida cuando se visualiza la entrada</string>
|
||||
<string name="enable_keep_screen_on_summary">Mantiene la pantalla encendida cuando se visualiza el apunte</string>
|
||||
<string name="enable_screenshot_mode_title">Modo captura de pantalla</string>
|
||||
<string name="enable_screenshot_mode_summary">Permite que aplicaciones de terceros graben o tomen pantallazos de la aplicación</string>
|
||||
<string name="show_entry_colors_summary">Muestra los colores de primer y segundo plano de una entrada</string>
|
||||
@@ -666,7 +663,7 @@
|
||||
<string name="ask">Preguntar</string>
|
||||
<string name="configure">Configurar</string>
|
||||
<string name="unlock_and_link_biometric">Enlace de desbloqueo del dispositivo</string>
|
||||
<string name="menu_appearance_settings_summary">Temas, colores, atributos</string>
|
||||
<string name="menu_appearance_settings_summary">Temas, colores, iconos, fuentes, atributos</string>
|
||||
<string name="unlock">Desbloquear</string>
|
||||
<string name="education_validate_entry_title">Validar la entrada</string>
|
||||
<string name="education_validate_entry_summary">No olvide validar tu inicio de sesión y guardar tu base de datos.\n\nSi se activa un bloqueo automático y olvidas que estabas haciendo una modificación, corres el riesgo de perder tus datos.</string>
|
||||
@@ -683,11 +680,52 @@
|
||||
<string name="style_name_dark">Oscuro</string>
|
||||
<string name="warning_database_info_changed_options_read_only">Recargue la base de datos con los últimos cambios.</string>
|
||||
<string name="nodes">Nodos</string>
|
||||
<string name="recursive_number_entries_summary">Calcula recursivamente el número de entradas en un grupo</string>
|
||||
<string name="recursive_number_entries_summary">Calcula recursivamente el número de apuntes en un grupo</string>
|
||||
<string name="warning_large_keyfile">No se recomienda agregar un archivo de clave grande , esto puede impedir que se abra la base de datos.</string>
|
||||
<string name="hide_templates_title">Ocultar plantillas</string>
|
||||
<string name="generate_keyfile">Generar archivo de claves</string>
|
||||
<string name="recursive_number_entries_title">Número recursivo de entradas</string>
|
||||
<string name="recursive_number_entries_title">Número recursivo de apuntes</string>
|
||||
<string name="hide_templates_summary">Las plantillas no se muestran</string>
|
||||
<string name="error_otp_secret_length">La clave secreta debe tener al menos %1$d caracteres.</string>
|
||||
<string name="entry_application_id">ID aplicación</string>
|
||||
<string name="warning_overwrite_data_title">¿Desea sobrescribir los datos existentes?</string>
|
||||
<string name="warning_overwrite_data_description">Esta acción sustituirá los datos existentes en el apuntes. Si el historial está habilitado, podrá recuperar los datos antiguos.</string>
|
||||
<string name="credential_provider">Proveedor de credenciales</string>
|
||||
<string name="passkeys_explanation_summary">Configure las claves de acceso para un inicio de sesión rápido y seguro sin contraseña</string>
|
||||
<string name="passkeys">Claves de acceso</string>
|
||||
<string name="passkeys_preference_title">Configuración de claves de acceso</string>
|
||||
<string name="passkeys_close_database_title">Cerrar base de datos</string>
|
||||
<string name="passkeys_close_database_summary">Cerrar la base de datos después de seleccionar una contraseña</string>
|
||||
<string name="passkeys_privileged_apps_summary">Administrar navegadores en la lista personalizada de aplicaciones privilegiadas</string>
|
||||
<string name="passkeys_privileged_apps_explanation">ADVERTENCIA: Una aplicación privilegiada actúa como puerta de enlace para recuperar el origen de una autenticación. Asegúrese de su legitimidad para evitar problemas de seguridad.</string>
|
||||
<string name="passkeys_privileged_apps_title">Aplicaciones privilegiadas</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">Aplicación no reconocida</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">%1$s intenta realizar una acción de claves de acceso.\n\n¿Añadirlo a la lista de aplicaciones con privilegios?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">Falta la firma</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">ADVERTENCIA: La clave de acceso se ha creado desde otro cliente o se ha eliminado la firma. Asegúrese de que la aplicación que desea autenticar forma parte del mismo servicio y es legítima para evitar problemas de seguridad.\nSi la aplicación es un navegador, no añada su firma al apunte, sino a la lista de aplicaciones privilegiadas en la configuración.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_message">%1$s no se reconoce e intenta autenticarse con una clave de acceso existente.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">¿Añadir firma de la aplicación al apunte de la clave de acceso?</string>
|
||||
<string name="passkeys_auto_select_title">Selección automática</string>
|
||||
<string name="passkeys_auto_select_summary">Seleccionar automáticamente si solo hay un apunte y la base de datos está abierta, solo si la aplicación solicitante es compatible</string>
|
||||
<string name="passkeys_backup_eligibility_title">Requisitos para la copia de seguridad</string>
|
||||
<string name="passkeys_backup_eligibility_summary">Determinar en el momento de la creación si se permite realizar copias de seguridad de la fuente de credenciales de clave pública</string>
|
||||
<string name="passkeys_backup_state_title">Estado de copia de seguridad</string>
|
||||
<string name="passkeys_backup_state_summary">Indique que las credenciales están respaldadas y protegidas contra la pérdida de un solo dispositivo</string>
|
||||
<string name="credential_provider_service_subtitle">Claves de acceso, proveedor de credenciales de autocompletar</string>
|
||||
<string name="passkey">Claves de acceso</string>
|
||||
<string name="passkey_service_name">Proveedor de credenciales KeePassDX</string>
|
||||
<string name="passkey_creation_description">Guardar clave de acceso en nuevo apunte</string>
|
||||
<string name="passkey_update_description">Actualizar clave de acceso en %1$s</string>
|
||||
<string name="passkey_selection_username">No se ha encontrado ninguna clave de acceso</string>
|
||||
<string name="passkey_selection_description">Seleccionar una clave de acceso existente</string>
|
||||
<string name="passkey_database_username">Base de datos KeePassDX</string>
|
||||
<string name="passkey_locked_database_description">Seleccionar para desbloquear</string>
|
||||
<string name="passkey_username">Nombre de usuario de clave de acceso</string>
|
||||
<string name="passkey_private_key">Clave privada clave de acceso</string>
|
||||
<string name="passkey_credential_id">Identificador de credencial de clave de acceso</string>
|
||||
<string name="passkey_user_handle">Identificador de usuario de clave de acceso</string>
|
||||
<string name="passkey_relying_party">Parte que confía en la clave de acceso</string>
|
||||
<string name="passkey_backup_eligibility">Requisitos para la copia de seguridad de la clave de acceso</string>
|
||||
<string name="passkey_backup_state">Estado de copia de seguridad de la clave de acceso</string>
|
||||
<string name="error_passkey_result">No se puede retornar la clave de acceso</string>
|
||||
</resources>
|
||||
|
||||
@@ -197,8 +197,6 @@
|
||||
<string name="hint_keyfile">Võtmefail</string>
|
||||
<string name="hint_length">Pikkus</string>
|
||||
<string name="password">Salasõna</string>
|
||||
<string name="hide_password_title">Peida salasõnad</string>
|
||||
<string name="hide_password_summary">Vakimisi peida salasõnad (***) maski taha</string>
|
||||
<string name="colorize_password_title">Värvi salasõnad</string>
|
||||
<string name="error_registration_read_only">Uue kirje salvestamine pole võimalik andmebaasis, milles on vaid lugemisõigus.</string>
|
||||
<string name="error_database_uri_null">Andmebaasi ühtset ressursiidentifikaatorit ei õnnestu laadida.</string>
|
||||
@@ -213,7 +211,6 @@
|
||||
<string name="list_groups_show_number_entries_title">Näita kirjete arvu</string>
|
||||
<string name="show_uuid_title">Näita UUID\'d</string>
|
||||
<string name="show_uuid_summary">Näita kirje või grupiga seotud UUID\'d</string>
|
||||
<string name="menu_hide_password">Peida salasõna</string>
|
||||
<string name="menu_showpass">Näita salasõna</string>
|
||||
<string name="error_cancel_by_user">Katkestatud kasutaja poolt.</string>
|
||||
<string name="error_driver_required">%1$s draiver on vajalik.</string>
|
||||
|
||||
@@ -93,8 +93,6 @@
|
||||
<string name="list_size_summary">Testuaren tamaina taldearen listan</string>
|
||||
<string name="loading_database">Datubasea kargatzen…</string>
|
||||
<string name="lowercase">minuskulak</string>
|
||||
<string name="hide_password_title">Pasahitza estali</string>
|
||||
<string name="hide_password_summary">Pasahitza estali modu lehenetsian</string>
|
||||
<string name="about">Honi buruz</string>
|
||||
<string name="menu_change_key_settings">Gako nagusia aldatu</string>
|
||||
<string name="settings">Ezarpenak</string>
|
||||
@@ -102,7 +100,6 @@
|
||||
<string name="menu_delete">Ezabatu</string>
|
||||
<string name="menu_donate">Dirua eman</string>
|
||||
<string name="menu_edit">Editatu</string>
|
||||
<string name="menu_hide_password">Pasahitza ezkutatu</string>
|
||||
<string name="menu_lock">Datu-basea blokeatu</string>
|
||||
<string name="menu_open">Ireki</string>
|
||||
<string name="menu_search">Bilatu</string>
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
<string name="menu_open">باز</string>
|
||||
<string name="menu_save_database">ذخیره پایگاه داده</string>
|
||||
<string name="menu_lock">بانک اطلاعاتی قفل</string>
|
||||
<string name="menu_hide_password">پنهان کردن رمز عبور</string>
|
||||
<string name="menu_cancel">لغو</string>
|
||||
<string name="menu_delete">حذف</string>
|
||||
<string name="menu_paste">جاگذاری</string>
|
||||
@@ -97,8 +96,6 @@
|
||||
<string name="copy_field">کپی %1$s</string>
|
||||
<string name="menu_change_key_settings">کلید اصلی را تغییر دهید</string>
|
||||
<string name="about">در باره</string>
|
||||
<string name="hide_password_summary">رمزهای عبور ماسک (***) به طور پیش فرض</string>
|
||||
<string name="hide_password_title">پنهان کردن رمزهای عبور</string>
|
||||
<string name="lowercase">ترجمه</string>
|
||||
<string name="loading_database">پایگاه داده بارگذاری…</string>
|
||||
<string name="creating_database">ایجاد پایگاه داده…</string>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
--><resources>
|
||||
<string name="feedback">Palaute</string>
|
||||
<string name="homepage">Kotisivu</string>
|
||||
<string name="about_description">KeePass-salasanahallintaohjelman Android-toteutus</string>
|
||||
<string name="about_description">KeePass-salasanahallintaohjelman Android-toteutus.</string>
|
||||
<string name="accept">Hyväksy</string>
|
||||
<string name="add_entry">Lisää uusi salasanatietue</string>
|
||||
<string name="add_group">Lisää ryhmä</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="application">Sovellus</string>
|
||||
<string name="menu_app_settings">Ohjelman asetukset</string>
|
||||
<string name="brackets">Hakasulkeet</string>
|
||||
<string name="file_manager_install_description">Tietokantojen avaamista, luomista ja tallentamista varten tarvitaan tiedostonhallintaohjelma, joka tukee ACTION_CREATE_DOCUMENT ja ACTION_OPEN_DOCUMENT Intent-toimintoja.</string>
|
||||
<string name="file_manager_install_description">Tietokantojen avaamista, luomista ja tallentamista varten tarvitaan tiedostonhallintaohjelma, joka tukee ACTION_CREATE_DOCUMENT ja ACTION_OPEN_DOCUMENT intent-toimintoja.</string>
|
||||
<string name="clipboard_cleared">Leikepöytä tyhjennetty</string>
|
||||
<string name="clipboard_error_title">Leikepöytävirhe</string>
|
||||
<string name="clipboard_error">Jotkin laitteet eivät anna sovellusten käyttää leikepöytää.</string>
|
||||
@@ -92,8 +92,6 @@
|
||||
<string name="list_size_summary">Tekstin koko ryhmälistauksessa</string>
|
||||
<string name="loading_database">Ladataan tietokantaa…</string>
|
||||
<string name="lowercase">pienet kirjaimet</string>
|
||||
<string name="hide_password_title">Piilota salasana</string>
|
||||
<string name="hide_password_summary">Piilota salasanat oletuksena</string>
|
||||
<string name="about">Tietoa</string>
|
||||
<string name="menu_change_key_settings">Vaihda pääsalasanaa</string>
|
||||
<string name="settings">Asetukset</string>
|
||||
@@ -101,7 +99,6 @@
|
||||
<string name="menu_delete">Poista</string>
|
||||
<string name="menu_donate">Lahjoita</string>
|
||||
<string name="menu_edit">Muokkaa</string>
|
||||
<string name="menu_hide_password">Piilota salasana</string>
|
||||
<string name="menu_lock">Lukitse tietokanta</string>
|
||||
<string name="menu_open">Avaa</string>
|
||||
<string name="menu_search">Etsi</string>
|
||||
@@ -145,7 +142,7 @@
|
||||
<string name="edit_entry">Muokkaa merkintää</string>
|
||||
<string name="error_disallow_no_credentials">Ainakin yksi pääsytieto tulee olla asetettuna.</string>
|
||||
<string name="error_load_database_KDF_memory">Avainta ei pystytty lataamaan. Kokeile vähentää KDF ”Muistin käyttöä”.</string>
|
||||
<string name="error_load_database">Tietokantaa ei pystytty avaamaan.</string>
|
||||
<string name="error_load_database">Tietokantaa ei pystytty lataamaan.</string>
|
||||
<string name="error_invalid_OTP">Virheellinen OTP salaisuus.</string>
|
||||
<string name="entry_otp">OTP</string>
|
||||
<string name="otp_algorithm">Algoritmi</string>
|
||||
@@ -173,7 +170,7 @@
|
||||
<string name="content_description_repeat_toggle_password_visibility">Toista salasanan näkyvyyden vaihto</string>
|
||||
<string name="content_description_keyfile_checkbox">Avaintiedoston valintaruutu</string>
|
||||
<string name="content_description_password_checkbox">Salasanan valintaruutu</string>
|
||||
<string name="content_description_file_information">Tietoja tiedostosta</string>
|
||||
<string name="content_description_file_information">Tiedoston tiedot</string>
|
||||
<string name="content_description_add_item">Lisää esine</string>
|
||||
<string name="content_description_add_group">Lisää ryhmä</string>
|
||||
<string name="content_description_add_entry">Lisää kohta</string>
|
||||
@@ -192,7 +189,7 @@
|
||||
<string name="menu_appearance_settings">Ulkonäkö</string>
|
||||
<string name="database_history">Historia</string>
|
||||
<string name="biometric">Biometrinen</string>
|
||||
<string name="unavailable">Tässä salasanatietokannassa ei ole vielä pääsytietoja.</string>
|
||||
<string name="unavailable">Ei saatavilla</string>
|
||||
<string name="keystore_not_accessible">Avainsäilöä ei ole kunnolla alustettu.</string>
|
||||
<string name="build_label">Koontiversio %1$s</string>
|
||||
<string name="warning_database_link_revoked">Tiedostoon pääsy evätty</string>
|
||||
@@ -235,7 +232,7 @@
|
||||
<string name="memory_usage_explanation">Avaimen johtamisfunktion käyttämän muistin määrä.</string>
|
||||
<string name="memory_usage">Muistin käyttö</string>
|
||||
<string name="kdf_explanation">Pääavain muunnetaan käyttäen satunnaista suolattua avaimen johtamisfunktiota, jotta salausalgoritmin avain voidaan generoida.</string>
|
||||
<string name="encryption_explanation">Salasanatietokannan salausalgoritmi, jota käytetään kaikelle datalle.</string>
|
||||
<string name="encryption_explanation">Salasanatietokannan salausalgoritmi, jota käytetään kaikelle datalle</string>
|
||||
<string name="password_size_title">Generoidun salasanan pituus</string>
|
||||
<string name="set_credential_provider_service_title">Aseta oletus automaattiselle täytölle</string>
|
||||
<string name="autofill_sign_in_prompt">Kirjaudu sisään KeePassDX:llä</string>
|
||||
@@ -257,10 +254,10 @@
|
||||
<string name="sort_menu">Järjestä</string>
|
||||
<string name="parallelism_explanation">Avaimen johtamisfunktion käyttämä rinnakkaisuuden aste (eli säikeiden määrä).</string>
|
||||
<string name="show_recent_files_title">Näytä viimeaikaiset tiedostot</string>
|
||||
<string name="remember_keyfile_locations_summary">Muista salasanatietokantojen avaintiedostojen sijainti</string>
|
||||
<string name="remember_keyfile_locations_title">Tallenna avaintiedostojen sijainti</string>
|
||||
<string name="remember_database_locations_summary">Muista salasanatietokantojen sijainti</string>
|
||||
<string name="remember_database_locations_title">Tallenna salasatietokantojen sijainti</string>
|
||||
<string name="remember_keyfile_locations_summary">Tallentaa avaintiedostojen tiedostosijannin</string>
|
||||
<string name="remember_keyfile_locations_title">Muista avaintiedostojen tiedostosijainnin</string>
|
||||
<string name="remember_database_locations_summary">Tallentaa tietokantojen tiedostosijainnit</string>
|
||||
<string name="remember_database_locations_title">Muista tietokantojen sijainnit</string>
|
||||
<string name="selection_mode">Valintatila</string>
|
||||
<string name="contains_duplicate_uuid_procedure">Ratkaise ongelma generoimalla uudet UUID:t kaksoiskappaleilla jatkaaksesi\?</string>
|
||||
<string name="contains_duplicate_uuid">Tietokanta sisältää päällekkäisiä UUID-tunnuksia.</string>
|
||||
@@ -286,9 +283,9 @@
|
||||
<string name="menu_form_filling_settings">Lomakkeen täyttö</string>
|
||||
<string name="copy_field">Kopio %1$s:sta</string>
|
||||
<string name="creating_database">Luodaan tietokantaa…</string>
|
||||
<string name="list_groups_show_number_entries_summary">Näytä tietueiden määrä ryhmässä</string>
|
||||
<string name="list_groups_show_number_entries_summary">Näyttää tietueiden määrän ryhmässä</string>
|
||||
<string name="list_groups_show_number_entries_title">Näytä tietueiden määrä</string>
|
||||
<string name="list_entries_show_username_summary">Näytä käyttäjänimet tietuelistoissa</string>
|
||||
<string name="list_entries_show_username_summary">Näyttää käyttäjänimet tietuelistoissa</string>
|
||||
<string name="list_entries_show_username_title">Näytä käyttäjänimet</string>
|
||||
<string name="invalid_db_same_uuid">%1$s samalla UUID:lla %2$s on jo olemassa.</string>
|
||||
<string name="file_not_found_content">Tiedostoa ei löytynyt. Yritä avata se uudelleen tiedostoselaimessasi.</string>
|
||||
@@ -367,7 +364,7 @@
|
||||
<string name="public_key">Julkinen avain</string>
|
||||
<string name="private_key">Salainen avain</string>
|
||||
<string name="error_word_reserved">Tämä sana on varattu eikä sitä voi käyttää.</string>
|
||||
<string name="error_otp_type">Olemassaolevaa OTP-tyyppiä ei ole tunnistettu tällä lomakkeella, ja sen validointi ei välttämättä enää tuota oikein tokenia.</string>
|
||||
<string name="error_otp_type">Olemassaolevaa OTP-tyyppiä ei ole tunnistettu tällä lomakkeella, ja sen validointi ei välttämättä enää tuota tokenia oikein.</string>
|
||||
<string name="show_uuid_summary">Näyttää tietueen tai ryhmän UUID-tunnisteen</string>
|
||||
<string name="generate_keyfile">Luo avaintiedosto</string>
|
||||
<string name="nodes">Solmut</string>
|
||||
@@ -388,16 +385,16 @@
|
||||
<string name="error_database_uri_null">Tietokannan URI-osoitetta ei voi palauttaa.</string>
|
||||
<string name="error_file_to_big">Lataamasi tiedosto on liian suuri.</string>
|
||||
<string name="error_remove_file">Virhe poistaessa tiedoston tietoja.</string>
|
||||
<string name="error_challenge_already_requested">Haaste on jo pyydetty</string>
|
||||
<string name="error_challenge_already_requested">Haaste on jo pyydetty.</string>
|
||||
<string name="error_response_already_provided">Vastaus on jo annettu.</string>
|
||||
<string name="error_no_response_from_challenge">Vastausta haasteeseen ei voitu saada.</string>
|
||||
<string name="error_unable_merge_database_kdb">Ei voitu yhdistää kdb-tietokantatiedostoon</string>
|
||||
<string name="error_unable_merge_database_kdb">Ei voitu yhdistää kdb-tietokantatiedostoon.</string>
|
||||
<string name="error_location_unknown">Tietokannan sijainti ei ole tiedossa, tietokannan toimintaa ei voida suorittaa.</string>
|
||||
<string name="error_hardware_key_unsupported">Laitteistoavainta ei tueta.</string>
|
||||
<string name="error_empty_key">Avain ei voi olla tyhjä.</string>
|
||||
<string name="corrupted_file">Korruptoitunut tiedosto.</string>
|
||||
<string name="passphrase">Salalause</string>
|
||||
<string name="error_registration_read_only">Uuden tietueen tallentaminen ei ole sallittua, kun tietokanta on vain lukutilassa</string>
|
||||
<string name="error_registration_read_only">Uuden tietueen tallentaminen ei ole sallittua, kun tietokanta on Vain luku -tilassa.</string>
|
||||
<string name="bank_name">Pankin nimi</string>
|
||||
<string name="warning_permanently_delete_nodes">Poista pysyvästi valitut solmut?</string>
|
||||
<string name="warning_database_info_changed">Tietokantatiedoston sisältämää tietoa on muutettu sovelluksen ulkopuolella.</string>
|
||||
@@ -416,10 +413,10 @@
|
||||
<string name="menu_security_settings_summary">Salaus, avaimen johtamisfunktio</string>
|
||||
<string name="master_key_settings_summary">Muutos, uudistus</string>
|
||||
<string name="remember_hardware_key_title">Muista laitteistoavaimet</string>
|
||||
<string name="remember_hardware_key_summary">Seuraa käytettyjä laitteistoavaimia</string>
|
||||
<string name="remember_hardware_key_summary">Tallenna käytetyt laitteistoavaimet</string>
|
||||
<string name="import_app_properties_title">Tuo sovellusasetukset</string>
|
||||
<string name="import_app_properties_summary">Valitse tiedosto tuodaksesi sovellusasetukset</string>
|
||||
<string name="error_import_app_properties">Virhe sovellusasetuksia tuodessa</string>
|
||||
<string name="error_import_app_properties">Virhe sovellusasetuksia tuodessa.</string>
|
||||
<string name="filter">Suodatin</string>
|
||||
<string name="warning_database_already_opened">Sulje avoinna oleva tietokanta ennen uuden avaamista</string>
|
||||
<string name="warning_empty_recycle_bin">Poista pysyvästi kaikki solmut roskakorista?</string>
|
||||
@@ -435,7 +432,7 @@
|
||||
<string name="export_app_properties_title">Vie sovellusasetukset</string>
|
||||
<string name="description_app_properties">KeePassDX ominaisuudet sovellusasetusten hallintaan</string>
|
||||
<string name="success_import_app_properties">Sovellusasetukset tuotu</string>
|
||||
<string name="error_export_app_properties">Virhe sovellusasetuksia viedessä</string>
|
||||
<string name="error_export_app_properties">Virhe sovellusasetuksia viedessä.</string>
|
||||
<string name="success_export_app_properties">Sovellusasetukset tuotu</string>
|
||||
<string name="error_otp_secret_length">Secret key on oltava vähintään %1$d merkkiä.</string>
|
||||
<string name="warning_database_info_changed_options">Yhdistä tiedot, korvaa ulkoiset muutokset tallentamalla tietokanta tai lataa se uudelleen uusimmilla muutoksilla.</string>
|
||||
@@ -463,4 +460,24 @@
|
||||
<string name="properties">Ominaisuudet</string>
|
||||
<string name="menu_appearance_settings_summary">Teemat, värit, kuvakkeet, fontit, attribuutit</string>
|
||||
<string name="device_credential">Laitteen tunnistetiedot</string>
|
||||
<string name="entry_application_id">Sovelluksen ID</string>
|
||||
<string name="warning_overwrite_data_title">Tallenna olemassaolevan datan päälle?</string>
|
||||
<string name="warning_overwrite_data_description">Tämä toiminto korvaa tietueessa jo olemassa olevan datan, mutta voit palauttaa vanhan datan jos historia on otettu käyttöön.</string>
|
||||
<string name="configure_biometric">Biometrisiä tunnistetietoja tai laitteen lukitusta ei ole otettu käyttöön.</string>
|
||||
<string name="credential_provider">Tunnistetietojen tarjoaja</string>
|
||||
<string name="passkeys">Pääsyavaimet</string>
|
||||
<string name="passkeys_explanation_summary">Ota pääsyavaimet käyttöön nopeaan ja turvalliseen salasanattomaan kirjautumiseen</string>
|
||||
<string name="passkeys_preference_title">Pääsyavainten asetukset</string>
|
||||
<string name="passkeys_close_database_title">Sulje tietokanta</string>
|
||||
<string name="passkeys_close_database_summary">Sulje tietokanta pääsyavaimen valitsemisen jälkeen</string>
|
||||
<string name="passkeys_privileged_apps_title">Luotetut sovellukset</string>
|
||||
<string name="passkeys_privileged_apps_summary">Hallinnoi selaimia luotettujen sovellustesi listassa</string>
|
||||
<string name="passkeys_privileged_apps_explanation">VAROITUS: Luotettu sovellus toimii porttina tunnistautumisen alkuperän selvittämiseen. Varmista sen aitous välttääksesi tietoturvaongelmia.</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">Sovellusta ei tunnistettu</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">%1$s yrittää pääsyavaintoimintoa.\n\nLisätäänkö se luotettujen sovellusten listaan?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">Allekirjoitus puuttuu</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">VAROITUS: Pääsyavain joko luotiin toisessa ohjelmassa tai sen allekirjoitus on poistettu. Varmista, että sovellus jonka haluat todentaa on osana samaa palvelua, ja että se on aito tietoturvaongelmien välttämiseksi.\nJos sovellus on selain, älä lisää sen allekirjoitusta tietueeseen, vaan lisää se asetuksissa luotettujen sovellusten listaan.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_message">%1$s on tuntematon ja se yrittää tunnistautua jo olemassaolevalla pääsyavaimella.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">Lisätäänkö sovelluksen allekirjoitus pääsyavaimen tietueeseen?</string>
|
||||
<string name="passkeys_auto_select_title">Automaattinen valinta</string>
|
||||
</resources>
|
||||
|
||||
@@ -218,8 +218,6 @@
|
||||
<string name="invalid_db_sig">Hindi makilala ang format ng database.</string>
|
||||
<string name="keyfile_is_empty">Walang laman ang keyfile.</string>
|
||||
<string name="length">Haba</string>
|
||||
<string name="hide_password_title">Itago ang mga password</string>
|
||||
<string name="hide_password_summary">I-mask ang mga password (***) bilang default</string>
|
||||
<string name="colorize_password_title">Kulayan ang mga password</string>
|
||||
<string name="colorize_password_summary">Kulayan ang mga password character ayon sa uri</string>
|
||||
<string name="list_entries_show_username_title">Ipakita ang mga username</string>
|
||||
@@ -258,7 +256,6 @@
|
||||
<string name="menu_paste">I-paste</string>
|
||||
<string name="menu_delete">Burahin</string>
|
||||
<string name="menu_cancel">Kanselahin</string>
|
||||
<string name="menu_hide_password">Itago ang password</string>
|
||||
<string name="menu_lock">I-lock ang database</string>
|
||||
<string name="menu_save_database">I-save ang data</string>
|
||||
<string name="menu_merge_database">I-merge ang data</string>
|
||||
|
||||
@@ -98,8 +98,6 @@
|
||||
<string name="list_size_summary">Taille du texte dans les éléments de liste</string>
|
||||
<string name="loading_database">Chargement de la base de données…</string>
|
||||
<string name="lowercase">Minuscules</string>
|
||||
<string name="hide_password_title">Masquer les mots de passe</string>
|
||||
<string name="hide_password_summary">Masque les mots de passe (***) par défaut</string>
|
||||
<string name="about">À propos</string>
|
||||
<string name="menu_change_key_settings">Modifier la clé principale</string>
|
||||
<string name="copy_field">%1$s copié</string>
|
||||
@@ -108,7 +106,6 @@
|
||||
<string name="menu_delete">Supprimer</string>
|
||||
<string name="menu_donate">Faire un don</string>
|
||||
<string name="menu_edit">Modifier</string>
|
||||
<string name="menu_hide_password">Masquer le mot de passe</string>
|
||||
<string name="menu_lock">Verrouiller la base de données</string>
|
||||
<string name="menu_open">Ouvrir</string>
|
||||
<string name="menu_search">Rechercher</string>
|
||||
|
||||
@@ -188,7 +188,6 @@
|
||||
<string name="corrupted_file">Ficheiro corrompido.</string>
|
||||
<string name="menu_keystore_remove_key">Borrar a clave do desbloqueo avanzado</string>
|
||||
<string name="loading_database">A carregar base de datos…</string>
|
||||
<string name="hide_password_summary">Mascarar contrasinais (***) por predefinición</string>
|
||||
<string name="list_size_summary">Tamaño do texto na lista de elementos</string>
|
||||
<string name="creating_database">A crear a base de datos…</string>
|
||||
<string name="menu_move">Mover</string>
|
||||
@@ -209,7 +208,6 @@
|
||||
<string name="colorize_password_title">Colorear contrasinais</string>
|
||||
<string name="colorize_password_summary">Colorear caracteres dos contrasinais por tipo</string>
|
||||
<string name="settings">Configuracións</string>
|
||||
<string name="menu_hide_password">Ocultar contrasinal</string>
|
||||
<string name="menu_lock">Bloquear base de datos</string>
|
||||
<string name="menu_save_database">Gardar datos</string>
|
||||
<string name="no_results">Sen resultados da procura</string>
|
||||
@@ -278,7 +276,6 @@
|
||||
<string name="list_entries_show_username_title">Mostrar nomes de usuario</string>
|
||||
<string name="hint_keyfile">Ficheiro clave</string>
|
||||
<string name="hint_pass">Contrasinal</string>
|
||||
<string name="hide_password_title">Ocultar contrasinais</string>
|
||||
<string name="lowercase">Minúsculas</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="copy_field">Copia de %1$s</string>
|
||||
|
||||
@@ -113,7 +113,6 @@
|
||||
<string name="list_groups_show_number_entries_summary">Prikazuje broj unosa u grupi</string>
|
||||
<string name="creating_database">Stvaranje baze podataka …</string>
|
||||
<string name="loading_database">Učitavanje baze podataka …</string>
|
||||
<string name="hide_password_title">Sakrij lozinke</string>
|
||||
<string name="menu_change_key_settings">Promjeni glavni ključ</string>
|
||||
<string name="settings">Postavke</string>
|
||||
<string name="menu_app_settings">Postavke aplikacije</string>
|
||||
@@ -127,7 +126,6 @@
|
||||
<string name="menu_copy">Kopiraj</string>
|
||||
<string name="menu_paste">Umetni</string>
|
||||
<string name="menu_delete">Izbriši</string>
|
||||
<string name="menu_hide_password">Sakrij lozinku</string>
|
||||
<string name="menu_lock">Zaključaj bazu podataka</string>
|
||||
<string name="menu_save_database">Spremi podatke</string>
|
||||
<string name="menu_open">Otvori</string>
|
||||
@@ -249,7 +247,6 @@
|
||||
<string name="list_size_title">Veličina elemenata popisa</string>
|
||||
<string name="list_size_summary">Veličina teksta u popisu elemenata</string>
|
||||
<string name="lowercase">Mala slova</string>
|
||||
<string name="hide_password_summary">Standardno sakrij lozinke (***)</string>
|
||||
<string name="about">O aplikaciji</string>
|
||||
<string name="copy_field">Kopija od %1$s</string>
|
||||
<string name="menu_move">Premjesti</string>
|
||||
|
||||
@@ -92,8 +92,6 @@
|
||||
<string name="list_size_summary">Szövegméret az elemlistában</string>
|
||||
<string name="loading_database">Adatbázis betöltése…</string>
|
||||
<string name="lowercase">Kisbetűk</string>
|
||||
<string name="hide_password_title">Jelszavak elrejtése</string>
|
||||
<string name="hide_password_summary">Jelszavak alapértelmezett elrejtése (***)</string>
|
||||
<string name="about">Névjegy</string>
|
||||
<string name="menu_change_key_settings">Mesterkulcs cseréje</string>
|
||||
<string name="settings">Beállítások</string>
|
||||
@@ -101,7 +99,6 @@
|
||||
<string name="menu_delete">Törlés</string>
|
||||
<string name="menu_donate">Támogatás</string>
|
||||
<string name="menu_edit">Szerkesztés</string>
|
||||
<string name="menu_hide_password">Jelszó elrejtése</string>
|
||||
<string name="menu_lock">Adatbázis zárolása</string>
|
||||
<string name="menu_open">Megnyitás</string>
|
||||
<string name="menu_search">Keresés</string>
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
<string name="menu_open">Buka</string>
|
||||
<string name="menu_save_database">Simpan data</string>
|
||||
<string name="menu_lock">Basis Data Terkunci</string>
|
||||
<string name="menu_hide_password">Sembunyikan Kata Sandi</string>
|
||||
<string name="menu_cancel">Batal</string>
|
||||
<string name="menu_delete">Hapus</string>
|
||||
<string name="menu_paste">Tempel</string>
|
||||
@@ -32,8 +31,6 @@
|
||||
<string name="copy_field">Salinan dari %1$s</string>
|
||||
<string name="menu_change_key_settings">Ubah Kunci Utama</string>
|
||||
<string name="about">Tentang</string>
|
||||
<string name="hide_password_summary">Secara otomatis tutupi kata sandi (***)</string>
|
||||
<string name="hide_password_title">Sembunyikan Kata Sandi</string>
|
||||
<string name="lowercase">Huruf Kecil</string>
|
||||
<string name="loading_database">Memuat basis data…</string>
|
||||
<string name="creating_database">Pembuatan basis data…</string>
|
||||
|
||||
@@ -94,8 +94,6 @@
|
||||
<string name="list_size_summary">Dimensione del testo nell\'elenco del gruppo</string>
|
||||
<string name="loading_database">Caricamento del database…</string>
|
||||
<string name="lowercase">Minuscole</string>
|
||||
<string name="hide_password_title">Nascondi le password</string>
|
||||
<string name="hide_password_summary">Maschera le password (***) in modo predefinito</string>
|
||||
<string name="about">Informazioni</string>
|
||||
<string name="menu_change_key_settings">Modifica chiave principale</string>
|
||||
<string name="settings">Impostazioni</string>
|
||||
@@ -103,7 +101,6 @@
|
||||
<string name="menu_delete">Elimina</string>
|
||||
<string name="menu_donate">Dona</string>
|
||||
<string name="menu_edit">Modifica</string>
|
||||
<string name="menu_hide_password">Nascondi password</string>
|
||||
<string name="menu_lock">Blocca database</string>
|
||||
<string name="menu_open">Apri</string>
|
||||
<string name="menu_search">Cerca</string>
|
||||
|
||||
@@ -90,8 +90,6 @@
|
||||
<string name="list_size_summary">גודל טקסט ברשימת הרכיבים</string>
|
||||
<string name="loading_database">טוען מסד נתונים…</string>
|
||||
<string name="lowercase">אות קטנה</string>
|
||||
<string name="hide_password_title">הסתר סיסמאות</string>
|
||||
<string name="hide_password_summary">הסווה סיסמאות (***) כברירת מחדל</string>
|
||||
<string name="about">אודות</string>
|
||||
<string name="menu_change_key_settings">שנה מפתח ראשי</string>
|
||||
<string name="settings">העדפות</string>
|
||||
@@ -99,7 +97,6 @@
|
||||
<string name="menu_delete">מחק</string>
|
||||
<string name="menu_donate">תרום</string>
|
||||
<string name="menu_edit">ערוך</string>
|
||||
<string name="menu_hide_password">הסתר סיסמה</string>
|
||||
<string name="menu_lock">נעל מסד נתונים</string>
|
||||
<string name="menu_open">פתח</string>
|
||||
<string name="menu_search">חיפוש</string>
|
||||
@@ -411,7 +408,7 @@
|
||||
<string name="autofill">מילוי אוטומטי</string>
|
||||
<string name="autofill_sign_in_prompt">התחבר עם KeePassDX</string>
|
||||
<string name="general">כללי</string>
|
||||
<string name="autofill_explanation_summary">הפעל מילוי אוטומטי כדי למלא במהירות טפסים ביישומים אחרים</string>
|
||||
<string name="autofill_explanation_summary">הגדר מילוי אוטומטי כדי למלא במהירות טפסים ביישומים אחרים</string>
|
||||
<string name="set_credential_provider_service_title">הגדר שירות מילוי אוטומטי ברירת מחדל</string>
|
||||
<string name="password_size_title">גודל סיסמה שנוצרה</string>
|
||||
<string name="password_size_summary">מגדיר גודל ברירת המחדל של הסיסמאות שנוצרו</string>
|
||||
@@ -420,7 +417,7 @@
|
||||
<string name="clipboard_warning">אם מחיקה אוטומטית של לוח ההעתקה נכשלת, מחק את ההיסטוריה שלו ידנית.</string>
|
||||
<string name="lock_database_screen_off_summary">נעל את מסד הנתונים לאחר כמה שניות ברגע שהמסך כבוי</string>
|
||||
<string name="lock_database_screen_off_title">נעילת מסך</string>
|
||||
<string name="lock_database_back_root_summary">נעל את מסד הנתונים כאשר המשתמש לוחץ על כפתור החזרה במסך הראשי</string>
|
||||
<string name="lock_database_back_root_summary">הקש על כפתור החזרה במסך הראשי בכדי לנעול את מסד הנתונים</string>
|
||||
<string name="biometric_unlock_enable_title">ביטול נעילה ביומטרית</string>
|
||||
<string name="biometric_unlock_enable_summary">מאפשר לך לסרוק את האמצעי הביומטרי שלך כדי לפתוח את מסד הנתונים</string>
|
||||
<string name="device_unlock_explanation_summary">השתמש בביטול נעילת המכשיר כדי לפתוח את מסד הנתונים ביתר קלות</string>
|
||||
@@ -604,7 +601,7 @@
|
||||
<string name="unlock_and_link_biometric">קישור ביטול נעילת מכשיר</string>
|
||||
<string name="encrypted_value_stored">סיסמה מוצפנת אוחסנה</string>
|
||||
<string name="unavailable">לא זמין</string>
|
||||
<string name="menu_appearance_settings_summary">ערכות נושא, צבעים, תכונות</string>
|
||||
<string name="menu_appearance_settings_summary">ערכות נושא, צבעים, סמלים, גופנים, תכונות</string>
|
||||
<string name="autofill_select_entry">בחר רשומה…</string>
|
||||
<string name="templates_group_enable_title">שימוש בתבניות</string>
|
||||
<string name="templates_group_enable_summary">השתמש בתבניות דינמיות כדי למלא את השדות של רשומה</string>
|
||||
@@ -686,4 +683,40 @@
|
||||
<string name="html_text_buy_pro">על ידי קניית גרסת הפרו, תהיה לך גישה ל<strong>סגנון החזותי</strong> הזה ותעזור במיוחד עם <strong>ההגשמה של פרויקטים קהילתיים.</strong></string>
|
||||
<string name="html_text_dev_feature_buy_pro">על ידי קניית גרסת ה<strong>פרו</strong>,</string>
|
||||
<string name="error_otp_secret_length">מפתח סודי חייב להיות לפחות %1$d תווים.</string>
|
||||
<string name="entry_application_id">מזהה אפליקציה</string>
|
||||
<string name="warning_overwrite_data_title">להחליף נתונים קיימים?</string>
|
||||
<string name="warning_overwrite_data_description">פעולה זו תחליף את הנתונים הקיימים בערך, ניתן לאחזר את הנתונים הישנים אם ההיסטוריה מופעלת.</string>
|
||||
<string name="passkeys">מפתחות גישה</string>
|
||||
<string name="passkeys_explanation_summary">הגדר מפתחות גישה בשביל התחברות ללא סיסמה מהירה ובטוחה</string>
|
||||
<string name="passkeys_preference_title">הגדרות מפתחות גישה</string>
|
||||
<string name="passkeys_close_database_title">סגור מסד נתונים</string>
|
||||
<string name="passkeys_close_database_summary">סגור את מסד הנתונים לאחר בחירת מפתח גישה</string>
|
||||
<string name="passkeys_privileged_apps_title">אפליקציות מורשות</string>
|
||||
<string name="passkeys_privileged_apps_summary">ניהול דפדפנים ברשימה המותאמת אישית של אפליקציות מורשות</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">אפליקציה לא מזוהה</string>
|
||||
<string name="passkeys_backup_eligibility_title">זכאות לגיבוי</string>
|
||||
<string name="passkeys_backup_eligibility_summary">קבע בעת היצירה האם מותר לגבות את מפתחות הגישה</string>
|
||||
<string name="passkeys_backup_state_title">מצב הגיבוי</string>
|
||||
<string name="passkeys_backup_state_summary">ציון שמפתחות הגישה מגובים ומוגנים מפני אובדן של מכשיר בודד</string>
|
||||
<string name="credential_provider_service_subtitle">ספק מפתחות גישה ומילוי אוטומטי</string>
|
||||
<string name="passkey">מפתח גישה</string>
|
||||
<string name="passkey_creation_description">שמו מפתח גישה ברשומה חדשה</string>
|
||||
<string name="passkey_update_description">עדכן מפתח גישה ב-%1$s</string>
|
||||
<string name="passkey_selection_username">לא נמצא מפתח גישה</string>
|
||||
<string name="passkey_selection_description">בחר מפתח גישה קיים</string>
|
||||
<string name="passkey_database_username">KeePassDX מסד נתונים</string>
|
||||
<string name="passkey_locked_database_description">בחר בשביל לפתוח</string>
|
||||
<string name="passkey_username">שם משתמש למפתח גישה</string>
|
||||
<string name="passkey_private_key">מפתח פרטי למפתח גישה</string>
|
||||
<string name="passkey_credential_id">מזהה ייחודי של מפתח גישה</string>
|
||||
<string name="passkey_user_handle">משתמש של מפתח גישה</string>
|
||||
<string name="passkey_relying_party">ספק מפתח גישה</string>
|
||||
<string name="passkey_backup_eligibility">זמינות לגיבוי מפתח ראשי</string>
|
||||
<string name="passkey_backup_state">מצב גיבוי מפתח ראשי</string>
|
||||
<string name="error_passkey_result">לא ניתן להחזיר מפתח גישה</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">חסר חתימה</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">הוסף חתימת יישום לרשומת מפתח גישה?</string>
|
||||
<string name="passkeys_auto_select_title">בחירה אוטומטית</string>
|
||||
<string name="passkeys_auto_select_summary">בחר אוטומטית אם רק רשומה אחת מתאימה ומסד הנתונים פתוח, ורק אם היישום המבקש מתאים</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">%1$s מנסה לבצע פעולה עם מפתח גישה.\n\nלהוסיך אותו לרשימת יישומים מורשים?</string>
|
||||
</resources>
|
||||
|
||||
@@ -159,8 +159,6 @@
|
||||
<string name="creating_database">データベースを作成しています…</string>
|
||||
<string name="loading_database">データベースを読み込んでいます…</string>
|
||||
<string name="lowercase">小文字</string>
|
||||
<string name="hide_password_title">パスワードを非表示にする</string>
|
||||
<string name="hide_password_summary">デフォルトでパスワードを隠します(***と表示)</string>
|
||||
<string name="about">概要</string>
|
||||
<string name="menu_change_key_settings">マスターキーを変更</string>
|
||||
<string name="copy_field">%1$s のコピー</string>
|
||||
@@ -178,7 +176,6 @@
|
||||
<string name="menu_paste">貼り付け</string>
|
||||
<string name="menu_delete">削除</string>
|
||||
<string name="menu_cancel">キャンセル</string>
|
||||
<string name="menu_hide_password">パスワードを非表示にする</string>
|
||||
<string name="menu_lock">データベースをロック</string>
|
||||
<string name="menu_save_database">保存する</string>
|
||||
<string name="menu_open">開く</string>
|
||||
|
||||
@@ -100,8 +100,6 @@
|
||||
<string name="list_size_summary">요소 목록 텍스트 크기</string>
|
||||
<string name="loading_database">데이터베이스 로딩 중…</string>
|
||||
<string name="lowercase">소문자</string>
|
||||
<string name="hide_password_title">비밀번호 숨기기</string>
|
||||
<string name="hide_password_summary">기본 비밀번호를 (***) 로 가리기</string>
|
||||
<string name="about">정보</string>
|
||||
<string name="menu_change_key_settings">마스터 키 바꾸기</string>
|
||||
<string name="copy_field">%1$s의 사본</string>
|
||||
@@ -116,7 +114,6 @@
|
||||
<string name="menu_paste">붙여넣기</string>
|
||||
<string name="menu_delete">삭제</string>
|
||||
<string name="menu_cancel">취소</string>
|
||||
<string name="menu_hide_password">비밀번호 숨기기</string>
|
||||
<string name="menu_lock">데이터베이스 잠그기</string>
|
||||
<string name="menu_open">열기</string>
|
||||
<string name="menu_search">검색</string>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||
--><resources>
|
||||
<string name="about_description">KeePass slaptažodžių tvarkyklės realizacija Android platformai</string>
|
||||
<string name="about_description">KeePassDX slaptažodžių tvarkyklės realizacija Android platformai</string>
|
||||
<string name="clipboard_cleared">Iškarpinė išvalyta</string>
|
||||
<string name="invalid_credentials">Nepavyko perskaityti prisijungimo duomenų.</string>
|
||||
<string name="feedback">Atsiliepimai</string>
|
||||
@@ -81,7 +81,6 @@
|
||||
<string name="entry_confpassword">Patvirtinti slaptažodį</string>
|
||||
<string name="invalid_db_sig">Nepavyko atpažinti duomenų bazės formato.</string>
|
||||
<string name="sort_db">Natūrali tvarka</string>
|
||||
<string name="menu_hide_password">Slėpti slaptažodį</string>
|
||||
<string name="app_timeout">Neveiklumas</string>
|
||||
<string name="clipboard_error_clear">Nepavyko išvalyti iškarpinės</string>
|
||||
<string name="list_size_summary">Teksto dydis grupės sąraše</string>
|
||||
@@ -92,7 +91,6 @@
|
||||
<string name="search">Įrašo pavadinimas/aprašymas</string>
|
||||
<string name="menu_change_key_settings">Pakeisti pagrindinį raktą</string>
|
||||
<string name="entry_accessed">Naudota</string>
|
||||
<string name="hide_password_title">Maskuoti slaptažodį</string>
|
||||
<string name="space">Tarpas</string>
|
||||
<string name="special">Specialus</string>
|
||||
<string name="uppercase">Didžiosios raidės</string>
|
||||
@@ -100,7 +98,6 @@
|
||||
<string name="minus">Minusas</string>
|
||||
<string name="underline">Pabraukimas</string>
|
||||
<string name="default_checkbox">Naudoti šią duomenų bazę kaip numatytąją</string>
|
||||
<string name="hide_password_summary">Slėpti slaptažodžius pagal nutylėjimą</string>
|
||||
<string name="invalid_algorithm">Neteisingas algoritmas.</string>
|
||||
<string name="error_invalid_path">Pasirūpininkite, kad kelias būtų teisingas.</string>
|
||||
<string name="education_unlock_summary">Įveskite slaptažodį ir/ar rakto failą, kad atrakintumėte savo duomenų bazę.
|
||||
@@ -296,8 +293,8 @@
|
||||
<string name="menu_reload_database">Iš naujo įkelti duomenis</string>
|
||||
<string name="menu_merge_from">Sujungti iš …</string>
|
||||
<string name="menu_keystore_remove_key">Ištrinti įrenginio atrakinimo raktą</string>
|
||||
<string name="menu_file_selection_read_only">Apsaugotas nuo rašymo</string>
|
||||
<string name="menu_open_file_read_and_write">Galima keisti</string>
|
||||
<string name="menu_file_selection_read_only">Apsaugotas nuo įrašymo</string>
|
||||
<string name="menu_open_file_read_and_write">Modifikuojama</string>
|
||||
<string name="menu_empty_recycle_bin">Ištuštinti šiukšliadėžę</string>
|
||||
<string name="no_results">Nėra paieškos rezultatų</string>
|
||||
<string name="no_url_handler">Įdiekite žiniatinklio naršyklę, kad atidaryti šį URL adresą.</string>
|
||||
@@ -376,7 +373,7 @@
|
||||
<string name="error_location_unknown">Duomenų bazės vieta nežinoma, duomenų bazės veiksmo atlikti negalima.</string>
|
||||
<string name="error_empty_key">Raktas negali būti tuščias.</string>
|
||||
<string name="corrupted_file">Sugadintas failas.</string>
|
||||
<string name="passphrase">Slapta frazė</string>
|
||||
<string name="passphrase">Slaptafrazė</string>
|
||||
<string name="menu_app_settings_summary">Paieška, užraktas, istorija, savybės</string>
|
||||
<string name="master_key_settings_summary">Keisti, atnaujinti</string>
|
||||
<string name="parallelism">Lygiagretumas</string>
|
||||
@@ -420,7 +417,7 @@
|
||||
<string name="warning_empty_keyfile_explanation">Raktų failo turinys niekada neturėtų būti keičiamas, o geriausiu atveju jame turėtų būti atsitiktinai sugeneruoti duomenys.</string>
|
||||
<string name="warning_remove_unlinked_attachment">Pašalinus nesusietus duomenis gali sumažėti saugyklos dydis, tačiau taip pat gali būti pašalinti \"KeePass\" papildiniams naudojami duomenys.</string>
|
||||
<string name="warning_database_info_changed">Saugyklos faile esanti informacija buvo pakeista už programos ribų.</string>
|
||||
<string name="rounds">Transformacijų kiekis</string>
|
||||
<string name="rounds">Transformacijos etapai</string>
|
||||
<string name="colorize_password_title">Slaptažodžių spalvinimas</string>
|
||||
<string name="colorize_password_summary">Slaptažodžio simbolių spalvinimas pagal tipą</string>
|
||||
<string name="show_otp_token_title">Rodyti OTP Token</string>
|
||||
@@ -432,4 +429,297 @@
|
||||
<string name="device_unlock_prompt_extract_credential_title">Įrenginio atrakinimo atpažinimas</string>
|
||||
<string name="lock_database_show_button_title">Rodyti užrakto mygtuką</string>
|
||||
<string name="content">Turinys</string>
|
||||
<string name="content_description_node_children">Mazgo vaikai</string>
|
||||
<string name="entry_application_id">Programos ID</string>
|
||||
<string name="error_otp_secret_length">Slaptasis raktas turi būti mažiausiai %1$d simbolių.</string>
|
||||
<string name="generate_keyfile">Generuoti rakto failą</string>
|
||||
<string name="nodes">Mazgai</string>
|
||||
<string name="recursive_number_entries_title">Įrašų rekursinis skaičius</string>
|
||||
<string name="recursive_number_entries_summary">Rekursiškai apskaičiuoja įrašų skaičių grupėje</string>
|
||||
<string name="show_otp_token_summary">Rodo OTP žetonus įrašų sąraše</string>
|
||||
<string name="menu_device_unlock_settings_summary">Biometrija, prietaiso kredencialai</string>
|
||||
<string name="kdf_explanation">Norint sugeneruoti raktą šifravimo algoritmui, pagrindinis raktas yra transformuojamas naudojant atsitiktinai su druska užpildytą rakto išvedimo funkciją.</string>
|
||||
<string name="warning_large_keyfile">Nerekomenduojama pridėti didelio rakto failo, tai gali sutrukdyti atidaryti duomenų bazę.</string>
|
||||
<string name="warning_database_notification_permission">Pranešimo leidimas leidžia rodyti duomenų bazės būseną ir užrakinti ją lengvai prieinamu mygtuku.\n\nJei neaktyvuosite šio leidimo, duomenų bazė, atidaryta fone, nebus matoma, jei priekyje yra kita programa.</string>
|
||||
<string name="warning_copy_permission">Reikalingas pranešimo leidimas iškarpinės pranešimo funkcijos naudojimui.</string>
|
||||
<string name="warning_overwrite_data_title">Perrašyti esamus duomenis?</string>
|
||||
<string name="warning_overwrite_data_description">Šis veiksmas pakeis esamus duomenis įraše, senus duomenis galite atgauti jei įjungta istorija.</string>
|
||||
<string name="build_label">Sukurta %1$s</string>
|
||||
<string name="keystore_not_accessible">Raktinė nėra tinkamai inicializuota.</string>
|
||||
<string name="unlock_and_link_biometric">Prietaiso atrakinimo nuoroda</string>
|
||||
<string name="device_unlock_prompt_store_credential_title">Nuoroda į prietaiso atrakinimą</string>
|
||||
<string name="device_unlock_prompt_extract_credential_message">Ištraukti duomenų bazės kredencialus su prietaiso atrakinimo duomenimis</string>
|
||||
<string name="encrypted_value_stored">Užšifruotas slaptažodis išsaugotas</string>
|
||||
<string name="device_unlock_invalid_key">Negalima perskaityti prietaiso atrakinimo rakto. Prašome jį ištrinti ir pakartoti atrakinimo atpažinimo procedūrą.</string>
|
||||
<string name="device_unlock_not_recognized">Nepavyko atpažinti prietaiso atrakinimo pėdsako</string>
|
||||
<string name="unavailable">Neprieinama</string>
|
||||
<string name="device_unlock_prompt_not_initialized">Nepavyko inicializuoti prietaiso atrakinimo užklausos.</string>
|
||||
<string name="device_credential">Prietaiso kredencialas</string>
|
||||
<string name="credential_provider">Kredencialo teikėjas</string>
|
||||
<string name="passkeys">Raktų sistemos</string>
|
||||
<string name="passkeys_explanation_summary">Konfigūruoti raktų sistemas greitam ir saugiam prisijungimui be slaptažodžio</string>
|
||||
<string name="passkeys_preference_title">Raktų sistemų nustatymai</string>
|
||||
<string name="passkeys_close_database_title">Uždaryti duomenų bazę</string>
|
||||
<string name="passkeys_close_database_summary">Uždaryti duomenų bazę po raktų sistemos pasirinkimo</string>
|
||||
<string name="passkeys_privileged_apps_title">Privilegijuotos programos</string>
|
||||
<string name="passkeys_privileged_apps_summary">Valdyti naršykles privilegijuotų programų sąraše</string>
|
||||
<string name="passkeys_privileged_apps_explanation">ĮSPĖJIMAS: Privilegijuota programa veikia kaip vartai autentifikacijos šaltinio gavimui. Užtikrinkite jos teisėtumą, kad išvengtumėte saugumo problemų.</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">Programa neatpažinta</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">%1$s bando atlikti prieigos rakto veiksmą.\n\nPridėti jį prie privilegijuotų programų sąrašo?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">Parašas trūksta</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">ĮSPĖJIMAS: Prieigos raktas buvo sukurtas iš kito kliento arba parašas buvo ištrintas. Užtikrinkite, kad programa, kurią norite autentifikuoti, yra tos pačios paslaugos dalis ir yra teisėta, kad išvengtumėte saugumo problemų.\nJei programa yra naršyklė, nepridėkite jos parašo prie įrašo, bet prie privilegijuotų programų sąrašo nustatymuose.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_message">%1$s neatpažinta ir bando autentifikuotis su esama raktų sistema.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">Pridėti programos parašą prie raktų sistemos įrašo?</string>
|
||||
<string name="passkeys_auto_select_title">Automatinis pasirinkimas</string>
|
||||
<string name="passkeys_auto_select_summary">Automatinis pasirinkimas jei tik vienas įrašas ir duomenų bazė atidaryta, tik jei prašanti programa suderinama</string>
|
||||
<string name="passkeys_backup_eligibility_title">Atsarginio kopijavimo tinkamumas</string>
|
||||
<string name="passkeys_backup_eligibility_summary">Nustatyti sukūrimo metu ar viešo rakto kredencialo šaltinis gali būti atsarginės kopijos</string>
|
||||
<string name="passkeys_backup_state_title">Atsarginio kopijavimo būsena</string>
|
||||
<string name="passkeys_backup_state_summary">Nurodyti, kad kredencialai yra atsarginėje kopijoje ir apsaugoti nuo vieno įrenginio praradimo</string>
|
||||
<string name="credential_provider_service_subtitle">Raktų sistemos, automatinio pildymo kredencialų teikėjas</string>
|
||||
<string name="clipboard">Iškarpinė</string>
|
||||
<string name="clipboard_explanation_summary">Kopijuoti įrašų laukus naudojant jūsų prietaiso iškarpinę</string>
|
||||
<string name="clipboard_notifications_title">Iškarpinės pranešimai</string>
|
||||
<string name="clipboard_notifications_summary">Rodyti iškarpinės pranešimus laukų kopijavimui žiūrint įrašą</string>
|
||||
<string name="clipboard_warning">Jei automatinis iškarpinės ištrynimas nepavyksta, ištrinkite jos istoriją rankiniu būdu.</string>
|
||||
<string name="lock_database_back_root_summary">Paspauskite \"Atgal\", kad užrakintumėte duomenų bazę, jei esate duomenų bazės šakniniame ekrane</string>
|
||||
<string name="device_unlock_tap_delete">Bakstelėkite, kad ištrintumėte įrenginio atrakinimo raktus</string>
|
||||
<string name="device_unlock_explanation_summary">Naudokite įrenginio atrakinimą, kad lengviau atvertumėte duomenų bazę</string>
|
||||
<string name="device_credential_unlock_enable_title">Įrenginio kredencialo atrakinimas</string>
|
||||
<string name="device_credential_unlock_enable_summary">Leidžia naudoti jūsų įrenginio kredencialą duomenų bazei atverti</string>
|
||||
<string name="biometric_auto_open_prompt_title">Automatinis atidarymo raginimas</string>
|
||||
<string name="biometric_auto_open_prompt_summary">Automatiškai prašyti įrenginio atrakinimo, jei duomenų bazė nustatyta jį naudoti</string>
|
||||
<string name="temp_device_unlock_enable_title">Laikinas įrenginio atrakinimas</string>
|
||||
<string name="temp_device_unlock_enable_summary">Nesaugoti jokio užšifruoto turinio įrenginio atrakinimui naudoti</string>
|
||||
<string name="temp_device_unlock_timeout_title">Įrenginio atrakinimo galiojimo pabaiga</string>
|
||||
<string name="temp_device_unlock_timeout_summary">Įrenginio atrakinimo naudojimo trukmė prieš ištrinant jo turinį</string>
|
||||
<string name="device_unlock_timeout">Įrenginio atrakinimo laukimo laikas</string>
|
||||
<string name="biometric_delete_all_key_title">Ištrinti šifravimo raktus</string>
|
||||
<string name="biometric_delete_all_key_summary">Ištrinti visus šifravimo raktus, susijusius su įrenginio atrakinimo atpažinimu</string>
|
||||
<string name="device_unlock_delete_all_key_warning">Ištrinti visus šifravimo raktus, susijusius su įrenginio atrakinimo atpažinimu?</string>
|
||||
<string name="device_unlock_keystore_warning">Ši funkcija išsaugos užšifruotus kredencialų duomenis jūsų įrenginio saugiam KeyStore.\n\nPriklausomai nuo operacinės sistemos vietinio API įgyvendinimo, jis gali neveikti visiškai.\n\nPatikrinkite KeyStore suderinamumą ir saugumą su jūsų įrenginio gamintoju ir naudojamos ROM kūrėju.</string>
|
||||
<string name="unavailable_feature_text">Nepavyko paleisti šios funkcijos.</string>
|
||||
<string name="unavailable_feature_hardware">Nepavyko rasti atitinkamos aparatinės įrangos.</string>
|
||||
<string name="database_data_remove_unlinked_attachments_summary">Pašalina priedus, esančius duomenų bazėje, bet nesusietus su įrašu</string>
|
||||
<string name="templates_group_enable_title">Šablonų naudojimas</string>
|
||||
<string name="templates_group_enable_summary">Naudoti dinaminius šablonus įrašo laukams užpildyti</string>
|
||||
<string name="templates_group_uuid_title">Šablonų grupė</string>
|
||||
<string name="max_history_items_title">Maksimalus skaičius</string>
|
||||
<string name="max_history_items_summary">Riboti istorijos elementų skaičių vienam įrašui</string>
|
||||
<string name="max_history_size_title">Maksimalus dydis</string>
|
||||
<string name="max_history_size_summary">Riboti istorijos dydį vienam įrašui</string>
|
||||
<string name="settings_database_recommend_changing_master_key_title">Rekomenduoti atnaujinimą</string>
|
||||
<string name="settings_database_recommend_changing_master_key_summary">Rekomenduoti pakeisti pagrindinį raktą (dienomis)</string>
|
||||
<string name="settings_database_force_changing_master_key_title">Priversti atnaujinti</string>
|
||||
<string name="settings_database_force_changing_master_key_summary">Reikalauti pakeisti pagrindinį raktą (dienomis)</string>
|
||||
<string name="settings_database_force_changing_master_key_next_time_title">Priversti atnaujinti kitą kartą</string>
|
||||
<string name="settings_database_force_changing_master_key_next_time_summary">Reikalauti pakeisti pagrindinį raktą kitą kartą (vieną kartą)</string>
|
||||
<string name="monospace_font_fields_enable_title">Lauko šriftas</string>
|
||||
<string name="monospace_font_fields_enable_summary">Pakeisti laukuose naudojamą šriftą geresniam simbolių matomumui</string>
|
||||
<string name="allow_copy_password_title">Iškarpinės patikimumas</string>
|
||||
<string name="allow_copy_password_summary">Leisti kopijuoti įrašo slaptažodį ir apsaugotus laukus į iškarpinę</string>
|
||||
<string name="allow_copy_password_warning">Įspėjimas: Iškarpinė yra bendra visoms programoms. Jei nukopijuojami jautrūs duomenys, kita programinė įranga gali juos atkurti.</string>
|
||||
<string name="enable">Įgalinti</string>
|
||||
<string name="disable">Išjungti</string>
|
||||
<string name="notification">Pranešimas</string>
|
||||
<string name="clear_clipboard_notification_title">Išvalyti uždarant</string>
|
||||
<string name="clear_clipboard_notification_summary">Užrakinti duomenų bazę, kai iškarpinės trukmė baigiasi arba pranešimas uždaromas po to, kai pradėjote ją naudoti</string>
|
||||
<string name="database_name_title">Duomenų bazės pavadinimas</string>
|
||||
<string name="database_description_title">Duomenų bazės aprašymas</string>
|
||||
<string name="database_default_username_title">Numatytasis vartotojo vardas</string>
|
||||
<string name="database_custom_color_title">Tinkinta duomenų bazės spalva</string>
|
||||
<string name="database_version_title">Duomenų bazės versija</string>
|
||||
<string name="text_appearance">Tekstas</string>
|
||||
<string name="application_appearance">Sąsaja</string>
|
||||
<string name="other">Kita</string>
|
||||
<string name="compression">Suspaudimas</string>
|
||||
<string name="compression_none">Nėra</string>
|
||||
<string name="compression_gzip">Gzip</string>
|
||||
<string name="recycle_bin">Šiukšliadėžė</string>
|
||||
<string name="templates">Šablonai</string>
|
||||
<string name="keyboard">Klaviatūra</string>
|
||||
<string name="magic_keyboard_title">Magikeyboard</string>
|
||||
<string name="magic_keyboard_explanation_summary">Aktyvuoti tinkintą klaviatūrą, užpildančią jūsų slaptažodžius ir visus tapatybės laukus</string>
|
||||
<string name="device_keyboard_setting_title">Įrenginio klaviatūros nustatymai</string>
|
||||
<string name="keyboard_name">Magikeyboard</string>
|
||||
<string name="keyboard_label">Magikeyboard (KeePassDX)</string>
|
||||
<string name="keyboard_setting_label">Magikeyboard nustatymai</string>
|
||||
<string name="keyboard_entry_category">Įrašas</string>
|
||||
<string name="keyboard_selection_entry_title">Įrašo pasirinkimas</string>
|
||||
<string name="keyboard_selection_entry_summary">Kai peržiūrite įrašą KeePassDX, užpildyti Magikeyboard tuo įrašu</string>
|
||||
<string name="keyboard_notification_entry_title">Pranešimo informacija</string>
|
||||
<string name="keyboard_notification_entry_summary">Rodyti pranešimą, kai įrašas yra prieinamas</string>
|
||||
<string name="keyboard_save_search_info_title">Išsaugoti bendrinamą informaciją</string>
|
||||
<string name="keyboard_save_search_info_summary">Bandyti išsaugoti bendrinamą informaciją atliekant rankinį įrašo pasirinkimą lengvesniam būsimam naudojimui</string>
|
||||
<string name="keyboard_notification_entry_clear_close_title">Išvalyti uždarant</string>
|
||||
<string name="keyboard_notification_entry_clear_close_summary">Uždaryti duomenų bazę uždarant pranešimą</string>
|
||||
<string name="keyboard_entry_timeout_title">Laukimo laikas</string>
|
||||
<string name="keyboard_entry_timeout_summary">Laukimo laikas klaviatūros įrašui išvalyti</string>
|
||||
<string name="keyboard_notification_entry_content_title_text">Įrašas</string>
|
||||
<string name="keyboard_notification_entry_content_title">%1$s prieinamas Magikeyboard</string>
|
||||
<string name="keyboard_notification_entry_content_text">%1$s</string>
|
||||
<string name="keyboard_appearance_category">Išvaizda</string>
|
||||
<string name="keyboard_theme_title">Klaviatūros tema</string>
|
||||
<string name="keyboard_keys_category">Klavišai</string>
|
||||
<string name="keyboard_auto_go_action_title">Automatinis klavišo veiksmas</string>
|
||||
<string name="keyboard_auto_go_action_summary">\"Eiti\" klavišo veiksmas po \"Lauko\" klavišo paspaudimo</string>
|
||||
<string name="keyboard_key_vibrate_title">Vibruojantys klavišų paspaudimai</string>
|
||||
<string name="keyboard_key_sound_title">Girdimi klavišų paspaudimai</string>
|
||||
<string name="keyboard_change">Perjungti klaviatūrą</string>
|
||||
<string name="keyboard_previous_database_credentials_title">Duomenų bazės prisijungimo duomenų ekranas</string>
|
||||
<string name="keyboard_previous_database_credentials_summary">Automatiškai perjungti atgal į ankstesnę klaviatūrą duomenų bazės prisijungimo duomenų ekrane</string>
|
||||
<string name="keyboard_previous_search_title">Paieškos ekranas</string>
|
||||
<string name="keyboard_previous_search_summary">Automatiškai perjungti atgal į ankstesnę klaviatūrą paieškos ekrane</string>
|
||||
<string name="keyboard_previous_fill_in_title">Persijungti atgal</string>
|
||||
<string name="keyboard_previous_fill_in_summary">Automatiškai persijungti atgal į ankstesnę klaviatūrą po \"Auto key action\" vykdymo</string>
|
||||
<string name="keyboard_previous_lock_title">Užrakinti duomenų bazę</string>
|
||||
<string name="keyboard_previous_lock_summary">Automatiškai persijungti atgal į ankstesnę klaviatūrą po duomenų bazės užrakinimo</string>
|
||||
<string name="custom_fields">Tinkinti laukai</string>
|
||||
<string name="back_to_previous_keyboard">Atgal į ankstesnę klaviatūrą</string>
|
||||
<string name="select_entry">Pasirinkti įrašą</string>
|
||||
<string name="backspace">Atgal</string>
|
||||
<string name="enter">Įvesti</string>
|
||||
<string name="autofill_close_database_title">Uždaryti duomenų bazę</string>
|
||||
<string name="autofill_close_database_summary">Uždaryti duomenų bazę po automatinio pildymo pasirinkimo</string>
|
||||
<string name="autofill_inline_suggestions_title">Tiesioginiai pasiūlymai</string>
|
||||
<string name="autofill_inline_suggestions_summary">Bandyti rodyti automatinio pildymo pasiūlymus tiesiogiai iš suderinamos klaviatūros</string>
|
||||
<string name="autofill_manual_selection_title">Rankinis pasirinkimas</string>
|
||||
<string name="autofill_manual_selection_summary">Rodyti parinktį, leidžiančią naudotojui pasirinkti duomenų bazės įrašą</string>
|
||||
<string name="autofill_save_search_info_title">Išsaugoti paieškos informaciją</string>
|
||||
<string name="autofill_save_search_info_summary">Bandyti išsaugoti paieškos informaciją atliekant rankinį įrašo pasirinkimą, kad būtų lengviau naudoti ateityje</string>
|
||||
<string name="autofill_ask_to_save_data_title">Klausti apie duomenų išsaugojimą</string>
|
||||
<string name="autofill_ask_to_save_data_summary">Klausti apie duomenų išsaugojimą, kai formos pildymas užbaigiamas</string>
|
||||
<string name="autofill_application_id_blocklist_title">Programų blokavimo sąrašas</string>
|
||||
<string name="autofill_application_id_blocklist_summary">Blokavimo sąrašas, kuris neleidžia automatiškai pildyti programų</string>
|
||||
<string name="autofill_web_domain_blocklist_title">Žiniatinklio domenų blokavimo sąrašas</string>
|
||||
<string name="autofill_web_domain_blocklist_summary">Blokavimo sąrašas, kuris neleidžia automatiškai pildyti žiniatinklio domenų</string>
|
||||
<string name="autofill_block">Blokuoti automatinį pildymą</string>
|
||||
<string name="autofill_block_restart">Paleiskite iš naujo programą, kurioje yra forma, kad aktyvuotumėte blokavimą.</string>
|
||||
<string name="error_save_read_only">Duomenų išsaugojimas neleidžiamas duomenų bazei, atidarytai tik skaitymui.</string>
|
||||
<string name="autofill_inline_suggestions_keyboard">Automatinio pildymo pasiūlymai pridėti.</string>
|
||||
<string name="allow_no_password_title">Leisti be pagrindinio rakto</string>
|
||||
<string name="allow_no_password_summary">Leidžia paspausti \"Atidaryti\" mygtuką, jei nėra pasirinkti jokie kredencialai</string>
|
||||
<string name="delete_entered_password_title">Ištrinti slaptažodį</string>
|
||||
<string name="delete_entered_password_summary">Ištrina įvestą slaptažodį po bandymo prisijungti prie duomenų bazės</string>
|
||||
<string name="enable_auto_save_database_title">Automatiškai išsaugoti duomenų bazę</string>
|
||||
<string name="enable_auto_save_database_summary">Išsaugoti duomenų bazę po kiekvieno svarbaus veiksmo (\"Modifikuojamame\" režime)</string>
|
||||
<string name="enable_keep_screen_on_title">Laikyti ekraną įjungtą</string>
|
||||
<string name="enable_keep_screen_on_summary">Laikyti ekraną įjungtą žiūrint arba redaguojant įrašą</string>
|
||||
<string name="enable_screenshot_mode_title">Ekrano nuotraukos režimas</string>
|
||||
<string name="enable_screenshot_mode_summary">Leisti trečiųjų šalių programoms įrašyti arba daryti ekrano nuotraukas programos</string>
|
||||
<string name="enable_education_screens_title">Mokomieji patarimai</string>
|
||||
<string name="enable_education_screens_summary">Paryškinti elementus, kad išmokti kaip veikia programa</string>
|
||||
<string name="reset_education_screens_title">Atstatyti mokomuosius patarimus</string>
|
||||
<string name="reset_education_screens_summary">Rodyti visą mokomąją informaciją dar kartą</string>
|
||||
<string name="reset_education_screens_text">Mokomieji patarimai atstatyti</string>
|
||||
<string name="education_create_database_title">Sukurkite savo duomenų bazės failą</string>
|
||||
<string name="education_create_database_summary">Sukurkite savo pirmąjį slaptažodžių valdymo failą.</string>
|
||||
<string name="education_select_database_title">Atverti esamą duomenų bazę</string>
|
||||
<string name="education_select_database_summary">Atverkite savo ankstesnį duomenų bazės failą iš failų naršyklės, kad tęstumėte jį naudoti.</string>
|
||||
<string name="education_new_node_title">Pridėti elementus į savo duomenų bazę</string>
|
||||
<string name="education_new_node_summary">Įrašai padeda valdyti jūsų skaitmenines tapatybes.\n\nGrupės (~aplankai) organizuoja įrašus jūsų duomenų bazėje.</string>
|
||||
<string name="education_search_title">Ieškoti per įrašus</string>
|
||||
<string name="education_search_summary">Įveskite pavadinimą, vartotojo vardą arba kitų laukelių turinį, kad gautumėte savo slaptažodžius.</string>
|
||||
<string name="education_device_unlock_title">Įrenginio duomenų bazės atrakinimas</string>
|
||||
<string name="education_device_unlock_summary">Susiekite savo slaptažodį su nuskaitytu biometriniu arba įrenginio kredencialu, kad greitai atrakintumėte savo duomenų bazę.</string>
|
||||
<string name="education_entry_edit_title">Redaguoti įrašą</string>
|
||||
<string name="education_entry_edit_summary">Redaguokite savo įrašą su tinkintais laukais. Duomenų telkinys gali būti nurodomas tarp skirtingų įrašo laukelių.</string>
|
||||
<string name="education_generate_password_title">Sukurti stiprų slaptažodį</string>
|
||||
<string name="education_generate_password_summary">Sugeneruokite stiprų slaptažodį, susietą su jūsų įrašu, lengvai apibrėžkite jį pagal formos kriterijus ir nepamirškite saugaus slaptažodžio.</string>
|
||||
<string name="education_validate_entry_title">Patvirtinti įrašą</string>
|
||||
<string name="education_validate_entry_summary">Prisiminkite patvirtinti savo įrašą ir išsaugoti savo duomenų bazę.\n\nJei automatinis užraktas yra aktyvuotas ir pamiršote, kad darėte modifikaciją, rizikuojate prarasti savo duomenis.</string>
|
||||
<string name="education_entry_new_field_title">Pridėti tinkintus laukus</string>
|
||||
<string name="education_entry_new_field_summary">Užregistruokite papildomą lauką, pridėkite reikšmę ir pasirinktinai apsaugokite jį.</string>
|
||||
<string name="education_add_attachment_title">Pridėti priedą</string>
|
||||
<string name="education_add_attachment_summary">Įkelkite priedą į savo įrašą, kad išsaugotumėte svarbius išorinius duomenis.</string>
|
||||
<string name="education_setup_OTP_title">Nustatyti OTP</string>
|
||||
<string name="education_setup_OTP_summary">Nustatykite vienkartinio slaptažodžio valdymą (HOTP / TOTP), kad sugeneruotumėte žetoną, reikalingą dviejų faktorių autentifikacijai (2FA).</string>
|
||||
<string name="education_read_only_title">Apsaugoti savo duomenų bazę nuo rašymo</string>
|
||||
<string name="education_field_copy_title">Kopijuoti lauką</string>
|
||||
<string name="education_field_copy_summary">Nukopijuoti laukai gali būti įklijuoti bet kur.\n\nNaudokite formos pildymo metodą, kurį pageidaujate.</string>
|
||||
<string name="education_lock_title">Užrakinti duomenų bazę</string>
|
||||
<string name="education_lock_summary">Greitai užrakinkite savo duomenų bazę, galite nustatyti programą, kad ji užsirakintų po kurio laiko ir kai ekranas išsijungia.</string>
|
||||
<string name="education_sort_title">Elementų rikiavimas</string>
|
||||
<string name="education_sort_summary">Pasirinkite kaip rikiuojami įrašai ir grupės.</string>
|
||||
<string name="education_donation_title">Dalyvauti</string>
|
||||
<string name="education_donation_summary">Padėkite padidinti stabilumą, saugumą ir pridėti daugiau funkcijų.</string>
|
||||
<string name="html_text_dev_feature_thanks">Labai dėkojame už jūsų indėlį.</string>
|
||||
<string name="html_text_dev_feature_work_hard">Mes sunkiai dirbame, kad greitai išleistume šią funkciją.</string>
|
||||
<string name="html_text_dev_feature_upgrade">Prisiminkite laikyti savo programą atnaujintą įdiegiant naujas versijas.</string>
|
||||
<string name="download">Parsisiųsti</string>
|
||||
<string name="contribute">Prisidėti</string>
|
||||
<string name="download_attachment">Parsisiųsti %1$s</string>
|
||||
<string name="upload_attachment">Įkelti %1$s</string>
|
||||
<string name="download_initialization">Inicijuojama…</string>
|
||||
<string name="download_progression">Vykdoma: %1$d%%</string>
|
||||
<string name="download_finalization">Užbaigiama…</string>
|
||||
<string name="download_complete">Užbaigta!</string>
|
||||
<string name="download_canceled">Atšaukta!</string>
|
||||
<string name="unit_byte">B</string>
|
||||
<string name="unit_kibibyte">KiB</string>
|
||||
<string name="unit_mebibyte">MiB</string>
|
||||
<string name="unit_gibibyte">GiB</string>
|
||||
<string name="entropy">Entropija: %1$s bit</string>
|
||||
<string name="entropy_high">Entropija: Aukšta</string>
|
||||
<string name="entropy_calculate">Entropija: Skaičiuojama…</string>
|
||||
<string name="at_least_one_char">Bent po vieną simbolį iš kiekvienos</string>
|
||||
<string name="exclude_ambiguous_chars">Neįtraukti dviprasmiškų simbolių</string>
|
||||
<string name="consider_chars_filter">Apsvarstyti simbolius</string>
|
||||
<string name="word_separator">Skyriklis</string>
|
||||
<string name="ignore_chars_filter">Ignoruoti simbolius</string>
|
||||
<string name="lower_case">mažosios raidės</string>
|
||||
<string name="upper_case">DIDŽIOSIOS RAIDĖS</string>
|
||||
<string name="title_case">Pavadinimo rašyba</string>
|
||||
<string name="character_count">Simbolių skaičius: %1$d</string>
|
||||
<string name="screenshot_mode_banner_text">Ekrano nuotraukos režimas</string>
|
||||
<string name="style_choose_title">Programos tema</string>
|
||||
<string name="style_choose_summary">Tema naudojama programoje</string>
|
||||
<string name="style_name_forest">Miškas</string>
|
||||
<string name="style_name_divine">Dieviškas</string>
|
||||
<string name="style_name_classic">Klasikinis</string>
|
||||
<string name="style_name_simple">Paprastas</string>
|
||||
<string name="style_name_moon">Mėnulis</string>
|
||||
<string name="style_name_sun">Saulė</string>
|
||||
<string name="style_name_reply">Atsakymas</string>
|
||||
<string name="style_name_kunzite">Kunzitas</string>
|
||||
<string name="style_name_follow_system">Sekti sistemą</string>
|
||||
<string name="style_brightness_title">Temos ryškumas</string>
|
||||
<string name="style_brightness_summary">Pasirinkti šviesias arba tamsias temas</string>
|
||||
<string name="style_name_light">Šviesi</string>
|
||||
<string name="style_name_dark">Tamsi</string>
|
||||
<string name="icon_section_standard">Standartinis</string>
|
||||
<string name="icon_section_custom">Tinkintas</string>
|
||||
<string name="icon_pack_choose_title">Piktogramų paketas</string>
|
||||
<string name="icon_pack_choose_summary">Piktogramų paketas naudojamas programoje</string>
|
||||
<string name="show_entry_colors_title">Įrašo spalvos</string>
|
||||
<string name="show_entry_colors_summary">Rodo pirmojo plano ir fono spalvas įrašui</string>
|
||||
<string name="hide_expired_entries_title">Slėpti nebegaliojančius įrašus</string>
|
||||
<string name="hide_templates_title">Slėpti šablonus</string>
|
||||
<string name="hide_templates_summary">Šablonai nėra rodomi</string>
|
||||
<string name="passkey">Prieigos raktas</string>
|
||||
<string name="passkey_service_name">KeePassDX kredencialų teikėjas</string>
|
||||
<string name="passkey_creation_description">Išsaugoti prieigos raktą naujame įraše</string>
|
||||
<string name="passkey_update_description">Atnaujinti prieigos raktą %1$s</string>
|
||||
<string name="passkey_selection_username">Prieigos raktas nerastas</string>
|
||||
<string name="passkey_selection_description">Pasirinkti esamą prieigos raktą</string>
|
||||
<string name="passkey_database_username">KeePassDX duomenų bazė</string>
|
||||
<string name="passkey_locked_database_description">Pasirinkti atrakinti</string>
|
||||
<string name="passkey_username">Prieigos rakto vartotojo vardas</string>
|
||||
<string name="passkey_private_key">Prieigos rakto privatus raktas</string>
|
||||
<string name="passkey_credential_id">Prieigos rakto kredencialo ID</string>
|
||||
<string name="passkey_user_handle">Prieigos rakto naudotojo rankena</string>
|
||||
<string name="passkey_relying_party">Prieigos rakto pasikliaujanti šalis</string>
|
||||
<string name="passkey_backup_eligibility">Prieigos rakto atsarginės kopijos tinkamumas</string>
|
||||
<string name="passkey_backup_state">Prieigos rakto atsarginės kopijos būsena</string>
|
||||
<string name="error_passkey_result">Nepavyko grąžinti prieigos rakto</string>
|
||||
<string name="html_about_contribution">Kad <strong>išlaikytume savo laisvę</strong>, <strong>ištaisytume klaidas</strong>, <strong>pridėtume funkcijų</strong> ir <strong>būtume visada aktyvūs</strong>, mes pasikliaujame jūsų <strong>indėliu</strong>.</string>
|
||||
<string name="education_read_only_summary">Pakeiskite atidarymo režimą sesijai.\n\n\"Raišymo apsauga\" apsaugo nuo netyčinių duomenų bazės pakeitimų.\n\"Modifikuojamas\" leidžia pridėti, ištrinti arba modifikuoti visus elementus kaip norite.</string>
|
||||
<string name="html_text_ad_free">Skirtingai nuo daugelio slaptažodžių valdymo programų, ši yra <strong>be reklamų</strong>, <strong>copylefted libre programinė įranga</strong> ir nerenka asmeninių duomenų savo serveriuose, nesvarbu kokią versiją naudojate.</string>
|
||||
<string name="html_text_buy_pro">Perkant pro versiją, turėsite prieigą prie šio <strong>vizualinio stiliaus</strong> ir ypač padėsite <strong>bendruomenės projektų realizacijai.</strong></string>
|
||||
<string name="html_text_feature_generosity">Šis <strong>vizualinis stilius</strong> yra prieinamas dėka jūsų dosnumo.</string>
|
||||
<string name="html_text_donation"><strong>Prisidėdami</strong> prie projekto <i>(pinigais, kodu, vertimu)</i>, padėsite jam gyventi ir klestėti, ir taip pat turėsite teisę į <strong>temos</strong> atrakinimo procedūrą.</string>
|
||||
<string name="html_text_dev_feature">Ši funkcija yra <strong>kūrimo stadijoje</strong> ir reikalauja jūsų <strong>indėlio</strong>, kad būtų prieinama greitai.</string>
|
||||
<string name="html_text_dev_feature_buy_pro">Perkant <strong>pro</strong> versiją,</string>
|
||||
<string name="html_text_dev_feature_contibute"><strong>Prisidėdami</strong>,</string>
|
||||
<string name="html_text_dev_feature_encourage">skatiname kūrėjus kurti <strong>naujas funkcijas</strong> ir <strong>ištaisyti klaidas</strong> pagal jūsų pastabas.</string>
|
||||
</resources>
|
||||
|
||||
@@ -89,8 +89,6 @@
|
||||
<string name="list_size_summary">Teksta izmērs ierakstos un grupu sarakstos</string>
|
||||
<string name="loading_database">Ielādēt datu bāzi…</string>
|
||||
<string name="lowercase">Mazie burti</string>
|
||||
<string name="hide_password_title">Sēpt paroles</string>
|
||||
<string name="hide_password_summary">Sēpt paroles *****</string>
|
||||
<string name="about">Par</string>
|
||||
<string name="menu_change_key_settings">Mainīt galveno paroli</string>
|
||||
<string name="settings">Iestatījumi</string>
|
||||
@@ -98,7 +96,6 @@
|
||||
<string name="menu_delete">Dzēst</string>
|
||||
<string name="menu_donate">Ziedot</string>
|
||||
<string name="menu_edit">Rediģēt</string>
|
||||
<string name="menu_hide_password">Paslēpt paroli</string>
|
||||
<string name="menu_lock">Bloķēt datu bāzi</string>
|
||||
<string name="menu_open">Atvērt</string>
|
||||
<string name="menu_search">Meklēšana</string>
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<string name="menu_search">തിരയുക</string>
|
||||
<string name="menu_security_settings">സുരക്ഷാ ക്രമീകരണങ്ങൾ</string>
|
||||
<string name="menu_database_settings">ഡാറ്റാബേസ് ക്രമീകരണങ്ങൾ</string>
|
||||
<string name="hide_password_summary">സ്ഥിരസ്ഥിതിയായി പാസ്വേഡുകൾ (***) മാസ്ക് ചെയ്യുക</string>
|
||||
<string name="invalid_algorithm">തെറ്റായ അൽഗോരിതം.</string>
|
||||
<string name="password">പാസ്സ്വേഡ്</string>
|
||||
<string name="hint_pass">പാസ്സ്വേഡ്</string>
|
||||
@@ -52,7 +51,6 @@
|
||||
<string name="menu_open">തുറക്കുക</string>
|
||||
<string name="menu_save_database">ഡാറ്റാബേസ് സംരക്ഷിക്കുക</string>
|
||||
<string name="menu_lock">ഡാറ്റാബേസ് ലോക്ക് ചെയ്യുക</string>
|
||||
<string name="menu_hide_password">പാസ്വേഡുകൾ മറയ്ക്കുക</string>
|
||||
<string name="menu_cancel">റദ്ദാക്കുക</string>
|
||||
<string name="menu_delete">ഇല്ലാതാക്കുക</string>
|
||||
<string name="menu_move">നീക്കുക</string>
|
||||
@@ -62,7 +60,6 @@
|
||||
<string name="menu_app_settings">അപ്ലിക്കേഷൻ ക്രമീകരണങ്ങൾ</string>
|
||||
<string name="settings">ക്രമീകരണങ്ങൾ</string>
|
||||
<string name="menu_change_key_settings">മാസ്റ്റർ കീ മാറ്റുക</string>
|
||||
<string name="hide_password_title">പാസ്വേഡുകൾ മറയ്ക്കുക</string>
|
||||
<string name="loading_database">ഡാറ്റാബേസ് ലോഡുചെയ്യുന്നു…</string>
|
||||
<string name="creating_database">ഡാറ്റാബേസ് സൃഷ്ടിക്കുന്നു…</string>
|
||||
<string name="list_entries_show_username_title">ഉപയോക്തൃനാമങ്ങൾ കാണിക്കുക</string>
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
<string name="list_size_summary">Tekststørrelse i elemenetlisten</string>
|
||||
<string name="loading_database">Laster database…</string>
|
||||
<string name="lowercase">Små bokstaver</string>
|
||||
<string name="hide_password_title">Masker passord</string>
|
||||
<string name="hide_password_summary">Skjul passord som forvalg</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="menu_change_key_settings">Endre hovednøkkel</string>
|
||||
<string name="copy_field">Kopi av%1$s</string>
|
||||
@@ -117,7 +115,6 @@
|
||||
<string name="menu_paste">Lim inn</string>
|
||||
<string name="menu_delete">Slett</string>
|
||||
<string name="menu_cancel">Avbryt</string>
|
||||
<string name="menu_hide_password">Skjul passord</string>
|
||||
<string name="menu_lock">Lås database</string>
|
||||
<string name="menu_open">Åpne</string>
|
||||
<string name="menu_search">Søk</string>
|
||||
|
||||
@@ -85,8 +85,6 @@
|
||||
<string name="list_size_summary">Tekstgrootte in de itemslijst</string>
|
||||
<string name="loading_database">Database laden…</string>
|
||||
<string name="lowercase">Kleine letters</string>
|
||||
<string name="hide_password_title">Wachtwoorden verbergen</string>
|
||||
<string name="hide_password_summary">Wachtwoorden maskeren (***)</string>
|
||||
<string name="about">Over</string>
|
||||
<string name="menu_change_key_settings">Hoofdsleutel wijzigen</string>
|
||||
<string name="settings">Instellingen</string>
|
||||
@@ -94,7 +92,6 @@
|
||||
<string name="menu_delete">Verwijderen</string>
|
||||
<string name="menu_donate">Doneren</string>
|
||||
<string name="menu_edit">Bewerken</string>
|
||||
<string name="menu_hide_password">Wachtwoord verbergen</string>
|
||||
<string name="menu_lock">Database vergrendelen</string>
|
||||
<string name="menu_open">Openen</string>
|
||||
<string name="menu_search">Zoeken</string>
|
||||
|
||||
@@ -81,8 +81,6 @@
|
||||
<string name="list_size_summary">Tekststorleik i gruppelista</string>
|
||||
<string name="loading_database">Lastar databasen …</string>
|
||||
<string name="lowercase">Små bokstavar</string>
|
||||
<string name="hide_password_title">Skjul passord</string>
|
||||
<string name="hide_password_summary">Skjul passord som forval</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="menu_change_key_settings">Endra hovudnøkkelen</string>
|
||||
<string name="settings">Innstillingar</string>
|
||||
@@ -90,7 +88,6 @@
|
||||
<string name="menu_delete">Slett</string>
|
||||
<string name="menu_donate">Doner</string>
|
||||
<string name="menu_edit">Endra</string>
|
||||
<string name="menu_hide_password">Skjul passord</string>
|
||||
<string name="menu_lock">Lås database</string>
|
||||
<string name="menu_open">Opne</string>
|
||||
<string name="menu_search">Søk</string>
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
<string name="menu_open">ਖੋਲ੍ਹੋ</string>
|
||||
<string name="menu_save_database">ਡਾਟਾਬੇਸ ਸੰਭਾਲੋ</string>
|
||||
<string name="menu_lock">ਡਾਟਾਬੇਸ ਲਾਕ ਕਰੋ</string>
|
||||
<string name="menu_hide_password">ਪਾਸਵਰਡ ਲੁਕਾਓ</string>
|
||||
<string name="menu_cancel">ਰੱਦ ਕਰੋ</string>
|
||||
<string name="menu_delete">ਹਟਾਓ</string>
|
||||
<string name="menu_paste">ਚੇਪੋ</string>
|
||||
@@ -105,8 +104,6 @@
|
||||
<string name="copy_field">%1$s ਦੀ ਕਾਪੀ</string>
|
||||
<string name="menu_change_key_settings">ਮਾਸਟਰ ਕੁੰਜੀ ਬਦਲੋ</string>
|
||||
<string name="about">ਇਸ ਬਾਰੇ</string>
|
||||
<string name="hide_password_summary">ਪਾਸਵਰਡਾਂ ਨੂੰ ਮੂਲ ਰੂਪ ਵਿੱਚ ਲੁਕਾਓ (***)</string>
|
||||
<string name="hide_password_title">ਪਾਸਵਰਡ ਲੁਕਾਓ</string>
|
||||
<string name="lowercase">ਛੋਟੇ ਅੱਖਰ (ਅੰਗਰੇਜ਼ੀ)</string>
|
||||
<string name="loading_database">…ਡਾਟਾਬੇਸ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ</string>
|
||||
<string name="creating_database">…ਡਾਟਾਬੇਸ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ</string>
|
||||
|
||||
@@ -81,8 +81,6 @@
|
||||
<string name="list_size_summary">Rozmiar tekstu na liście elementów</string>
|
||||
<string name="loading_database">Wczytywanie bazy danych…</string>
|
||||
<string name="lowercase">Małe litery</string>
|
||||
<string name="hide_password_title">Ukryj hasła</string>
|
||||
<string name="hide_password_summary">Domyślnie maskuj hasła (***)</string>
|
||||
<string name="about">O aplikacji</string>
|
||||
<string name="menu_change_key_settings">Zmień klucz główny</string>
|
||||
<string name="settings">Ustawienia</string>
|
||||
@@ -90,7 +88,6 @@
|
||||
<string name="menu_delete">Usuń</string>
|
||||
<string name="menu_donate">Wspomóż</string>
|
||||
<string name="menu_edit">Edytuj</string>
|
||||
<string name="menu_hide_password">Ukryj hasło</string>
|
||||
<string name="menu_lock">Zablokuj bazę danych</string>
|
||||
<string name="menu_open">Otwórz</string>
|
||||
<string name="menu_search">Szukaj</string>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
--><resources>
|
||||
<string name="feedback">Comentários</string>
|
||||
<string name="homepage">Página inicial</string>
|
||||
<string name="about_description">Implementação para Android do gerenciador de senhas KeePass.</string>
|
||||
<string name="about_description">Implementação do gerenciador de senhas KeePass no Android.</string>
|
||||
<string name="accept">Aceitar</string>
|
||||
<string name="add_entry">Adicionar entrada</string>
|
||||
<string name="add_group">Adicionar grupo</string>
|
||||
@@ -29,7 +29,7 @@
|
||||
<string name="application">Aplicativo</string>
|
||||
<string name="menu_app_settings">Configurações do aplicativo</string>
|
||||
<string name="brackets">Parênteses</string>
|
||||
<string name="file_manager_install_description">Um gerenciador de arquivos que aceita a ação Intenção ACTION_CREATE_DOCUMENT e ACTION_OPEN_DOCUMENT é necessário para criar, abrir e salvar arquivos de banco de dados.</string>
|
||||
<string name="file_manager_install_description">Um gerenciador de arquivos que aceita a ação de intenção ACTION_CREATE_DOCUMENT e ACTION_OPEN_DOCUMENT é necessário para criar, abrir e salvar arquivos de banco de dados.</string>
|
||||
<string name="clipboard_cleared">Área de transferência limpa</string>
|
||||
<string name="clipboard_timeout">Tempo limite para a área de transferência</string>
|
||||
<string name="clipboard_timeout_summary">Duração do armazenamento na área de transferência (se suportado pelo seu dispositivo)</string>
|
||||
@@ -83,8 +83,6 @@
|
||||
<string name="list_size_summary">Tamanho do texto na lista de grupos</string>
|
||||
<string name="loading_database">Carregando banco de dados…</string>
|
||||
<string name="lowercase">Letras minúsculas</string>
|
||||
<string name="hide_password_title">Esconder senhas</string>
|
||||
<string name="hide_password_summary">Mascarar senhas (***) por padrão</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="menu_change_key_settings">Modificar a chave-mestra</string>
|
||||
<string name="settings">Configurações</string>
|
||||
@@ -92,7 +90,6 @@
|
||||
<string name="menu_delete">Deletar</string>
|
||||
<string name="menu_donate">Doar</string>
|
||||
<string name="menu_edit">Editar</string>
|
||||
<string name="menu_hide_password">Esconder senha</string>
|
||||
<string name="menu_lock">Bloquear banco de dados</string>
|
||||
<string name="menu_open">Abrir</string>
|
||||
<string name="menu_search">Buscar</string>
|
||||
@@ -303,7 +300,7 @@
|
||||
<string name="selection_mode">Modo seleção</string>
|
||||
<string name="do_not_kill_app">Não feche o aplicativo…</string>
|
||||
<string name="lock_database_back_root_title">Pressionar \'Voltar\' para bloquear</string>
|
||||
<string name="lock_database_back_root_summary">Se estiver na tela raiz da base de dados, o botão \"Voltar\" irá trancá-la</string>
|
||||
<string name="lock_database_back_root_summary">Pressione \'Voltar\' para bloquear o banco de dados se você estiver na tela principal do banco de dados</string>
|
||||
<string name="clear_clipboard_notification_title">Limpar ao fechar</string>
|
||||
<string name="clear_clipboard_notification_summary">Bloquear o banco de dados quando a duração da área de transferência expirar ou a notificação for fechada depois do início do uso</string>
|
||||
<string name="recycle_bin">Lixeira</string>
|
||||
@@ -330,7 +327,7 @@
|
||||
<string name="content_description_password_checkbox">Caixa de seleção da senha</string>
|
||||
<string name="content_description_keyfile_checkbox">Caixa de seleção do arquivo-chave</string>
|
||||
<string name="content_description_repeat_toggle_password_visibility">Repetir mudança de visibilidade da senha</string>
|
||||
<string name="content_description_background">Plano de fundo</string>
|
||||
<string name="content_description_background">Segundo plano</string>
|
||||
<string name="content_description_update_from_list">Atualizar</string>
|
||||
<string name="content_description_keyboard_close_fields">Campos fechados</string>
|
||||
<string name="error_create_database_file">Impossibilitado de criar um banco de dados com essa senha e arquivo-chave.</string>
|
||||
@@ -473,7 +470,7 @@
|
||||
<string name="error_database_uri_null">O URI do banco de dados não pode ser recuperado.</string>
|
||||
<string name="error_field_name_already_exists">O nome do campo já existe.</string>
|
||||
<string name="error_registration_read_only">Não é permitido salvar um novo item em um banco de dados somente de leitura.</string>
|
||||
<string name="error_otp_type">O tipo de OTP existente não é reconhecido por este formulário, sua validação pode não gerar mais o token corretamente.</string>
|
||||
<string name="error_otp_type">O tipo de OTP existente não é reconhecido por este formulário, e sua validação pode não gerar mais o token corretamente.</string>
|
||||
<string name="error_word_reserved">Esta palavra é reservada e não pode ser usada.</string>
|
||||
<string name="version">Versão</string>
|
||||
<string name="template">Modelo</string>
|
||||
@@ -663,7 +660,7 @@
|
||||
<string name="auto_type">Digitação automática</string>
|
||||
<string name="content_description_hardware_key_checkbox">Caixa de verificação da chave física</string>
|
||||
<string name="merge_success">Merge concluído com sucesso</string>
|
||||
<string name="info">Info</string>
|
||||
<string name="info">Informação</string>
|
||||
<string name="menu_device_unlock_settings_summary">Biometria, credencial do dispositivo</string>
|
||||
<string name="menu_database_settings_summary">Metadados, lixeira, modelos, histórico</string>
|
||||
<string name="menu_security_settings_summary">Criptografia, função de derivação chave</string>
|
||||
@@ -707,20 +704,42 @@
|
||||
<string name="error_otp_secret_length">Chave secreta deve ter pelo menos %1$d caracteres.</string>
|
||||
<string name="warning_overwrite_data_title">Sobrescrever dados existentes?</string>
|
||||
<string name="warning_overwrite_data_description">Esta ação irá substituir os dados existentes na entrada, você pode recuperar os dados antigos se o histórico estiver habilitado.</string>
|
||||
<string name="credential_provider">Provedor da credencial</string>
|
||||
<string name="credential_provider">Provedor de credencial</string>
|
||||
<string name="passkeys_privileged_apps_summary">Gerencie navegadores na lista customizada de aplicações privilegiadas</string>
|
||||
<string name="passkeys_privileged_apps_explanation">AVISO: Um aplicativo privilegiado age como portão para obter a origem de uma autenticação. Certifique sua legitimidade para evitar problemas de segurança.</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">App não reconhecido</string>
|
||||
<string name="passkeys_privileged_apps_ask_message">%1$s tenta fazer uma ação de Passkey.\n\nAdicionar à lista de aplicativos privilegiados?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">Assinatura faltando</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">AVISO: A Passkey foi criada de outro cliente ou a assinatura foi deletada. Certifique que o aplicativo que você quer autenticar é parte do mesmo serviço e é legítimo para evitar problemas de segurança.\nSe o aplicativo é um navegador, não adicione sua assinatura à entrada, mas à lista de aplicativos privilegiados nas configurações.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_explanation">AVISO: A chave de acesso foi criada a partir de outro cliente ou a assinatura foi excluída. Certifique-se de que o aplicativo que você deseja autenticar faz parte do mesmo serviço e é legítimo para evitar problemas de segurança.\nSe o aplicativo for um navegador, não adicione sua assinatura à entrada, mas à lista de aplicativos privilegiados nas configurações.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_message">%1$s não é reconhecido e tenta autenticar com uma Passkey existente.</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">Adicionar assinatura de app à entrada de Passkey?</string>
|
||||
<string name="passkeys_missing_signature_app_ask_question">Adicionar a assinatura do aplicativo à entrada de chave de acesso?</string>
|
||||
<string name="passkeys_auto_select_title">Auto selecionar</string>
|
||||
<string name="passkeys_auto_select_summary">Auto selecionar se só uma entrada e a base de dados estiverem abertas, apenas se o app solicitante for compatível</string>
|
||||
<string name="passkeys_auto_select_summary">Selecionar automaticamente se houver apenas uma entrada e o banco de dados estiver aberto, apenas se o aplicativo solicitante for compatível</string>
|
||||
<string name="passkeys_backup_eligibility_title">Elegibilidade de Backup</string>
|
||||
<string name="passkeys_backup_eligibility_summary">Determine no tempo de criação se é permitido que seja feito o backup da fonte da credencial de chaves públicas</string>
|
||||
<string name="passkeys_backup_state_title">Estado do Backup</string>
|
||||
<string name="passkey">Passkey</string>
|
||||
<string name="passkey">Chave de acesso</string>
|
||||
<string name="passkey_service_name">Provedor de Credenciais KeePassDX</string>
|
||||
<string name="passkeys">Chaves de acesso</string>
|
||||
<string name="passkeys_explanation_summary">Configure Chaves de Acesso para um login rápido e seguro sem senha</string>
|
||||
<string name="passkeys_preference_title">Configurações de chaves de acesso</string>
|
||||
<string name="passkeys_close_database_title">Fechar banco de dados</string>
|
||||
<string name="passkeys_close_database_summary">Fechar o banco de dados após selecionar uma chave de acesso</string>
|
||||
<string name="passkeys_privileged_apps_title">Aplicativos privilegiados</string>
|
||||
<string name="passkeys_backup_state_summary">Indica quando as credenciais estiverem armazenadas e protegidas contra a perda de um dispositivo</string>
|
||||
<string name="credential_provider_service_subtitle">Chaves de acesso, preenchimento automático provedor de credenciais</string>
|
||||
<string name="passkey_creation_description">Salvar chave de acesso na nova entrada</string>
|
||||
<string name="passkey_update_description">Atualizar chave de acesso em %1$s</string>
|
||||
<string name="passkey_selection_username">Nenhuma chave de acesso encontrada</string>
|
||||
<string name="passkey_selection_description">Selecione uma chave de acesso existente</string>
|
||||
<string name="passkey_database_username">Banco de dados KeePassDX</string>
|
||||
<string name="passkey_locked_database_description">Selecione para desbloquear</string>
|
||||
<string name="passkey_username">Nome da chave de acesso</string>
|
||||
<string name="passkey_private_key">Chavde de acesso privada</string>
|
||||
<string name="passkey_credential_id">ID de credencial de chave de acesso</string>
|
||||
<string name="passkey_user_handle">Nome de usuário da chave de acesso</string>
|
||||
<string name="passkey_backup_eligibility">Elegibilidade para Backup de chave de acesso</string>
|
||||
<string name="passkey_backup_state">Status de backup da chave de acesso</string>
|
||||
<string name="error_passkey_result">Incapaz de retornar a chave de acesso</string>
|
||||
<string name="passkey_relying_party">Chave de acesso com autenticador externo</string>
|
||||
</resources>
|
||||
|
||||
@@ -93,8 +93,6 @@
|
||||
<string name="list_size_summary">Tamanho do texto na lista de grupos</string>
|
||||
<string name="loading_database">A carregar a base de dados…</string>
|
||||
<string name="lowercase">Minúsculas</string>
|
||||
<string name="hide_password_title">Ocultar palavras-passe</string>
|
||||
<string name="hide_password_summary">Mascarar palavras-passe (***) por predefinição</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="menu_change_key_settings">Alterar chave mestra</string>
|
||||
<string name="settings">Configurações</string>
|
||||
@@ -102,7 +100,6 @@
|
||||
<string name="menu_delete">Eliminar</string>
|
||||
<string name="menu_donate">Donativos</string>
|
||||
<string name="menu_edit">Editar</string>
|
||||
<string name="menu_hide_password">Ocultar palavra-chave</string>
|
||||
<string name="menu_lock">Bloquear base de dados</string>
|
||||
<string name="menu_open">Abrir</string>
|
||||
<string name="menu_search">Pesquisar</string>
|
||||
|
||||
@@ -142,7 +142,6 @@
|
||||
<string name="menu_search">Pesquisar</string>
|
||||
<string name="menu_open">Abrir</string>
|
||||
<string name="menu_lock">Bloquear base de dados</string>
|
||||
<string name="menu_hide_password">Ocultar palavra-chave</string>
|
||||
<string name="menu_edit">Editar</string>
|
||||
<string name="menu_donate">Donativos</string>
|
||||
<string name="menu_delete">Eliminar</string>
|
||||
@@ -246,8 +245,6 @@
|
||||
<string name="auto_focus_search_summary">Solicitar uma pesquisa quando abrir a base de dados</string>
|
||||
<string name="auto_focus_search_title">Pesquisa rápida</string>
|
||||
<string name="about">Sobre</string>
|
||||
<string name="hide_password_summary">Mascarar palavras-passe (***) por predefinição</string>
|
||||
<string name="hide_password_title">Ocultar palavras-passe</string>
|
||||
<string name="html_about_contribution">Para <strong>manter a liberdade</strong>, <strong>corrigir erros</strong>, <strong>adicionar funcionalidades</strong> e <strong>para sermos sempre ativos</strong>, contamos com sua <strong>contribuição</strong>.</string>
|
||||
<string name="homepage">Página inicial</string>
|
||||
<string name="feedback">Comentários</string>
|
||||
|
||||
@@ -163,7 +163,6 @@
|
||||
<string name="menu_paste">Lipește</string>
|
||||
<string name="menu_delete">Șterge</string>
|
||||
<string name="menu_cancel">Anulare</string>
|
||||
<string name="menu_hide_password">Ascunde parola</string>
|
||||
<string name="menu_lock">Blocare bază de date</string>
|
||||
<string name="menu_save_database">Salvare date</string>
|
||||
<string name="menu_open">Deschidere</string>
|
||||
@@ -180,8 +179,6 @@
|
||||
<string name="no_results">Nu există rezultate de căutare</string>
|
||||
<string name="html_about_licence">KeePassDX © %1$d Kunzisoft este <strong>open source</strong> și <strong>fără reclame</strong>. \nEste furnizat ca atare, sub licență <strong>GPLv3</strong>, fără nicio garanție.</string>
|
||||
<string name="html_about_contribution">Pentru a ne <strong>păstra libertatea</strong>, <strong>pentru a remedia erori</strong>, <strong>pentru a adăuga funcții</strong> și <strong>pentru a fi mereu activi</strong>, ne bazăm pe <strong>contribuția</strong> dvs.</string>
|
||||
<string name="hide_password_title">Ascundeți parolele</string>
|
||||
<string name="hide_password_summary">Mascați parolele (***) în mod implicit</string>
|
||||
<string name="about">Despre</string>
|
||||
<string name="no_url_handler">Instalați un browser web pentru a deschide această adresă URL.</string>
|
||||
<string name="select_database_file">Deschideți seiful existent</string>
|
||||
@@ -546,7 +543,7 @@
|
||||
<string name="error_import_app_properties">Eroare în timpul importării setărilor aplicației.</string>
|
||||
<string name="warning_exact_alarm">Nu ați permis aplicației să utilizeze o alarmă exactă. Ca urmare, funcțiile care necesită un cronometru nu se vor face cu o oră exactă.</string>
|
||||
<string name="warning_database_info_reloaded">Reîncărcarea bazei de date va șterge datele modificate local.</string>
|
||||
<string name="menu_appearance_settings_summary">Teme, culori, atribute</string>
|
||||
<string name="menu_appearance_settings_summary">Teme, culori, incoane, fonturi, atribute.</string>
|
||||
<string name="autofill_preference_title">Setări de autocompletare</string>
|
||||
<string name="warning_replace_file">Încărcarea acestui fișier îl va înlocui pe cel existent.</string>
|
||||
<string name="content">Conținut</string>
|
||||
@@ -698,4 +695,17 @@
|
||||
<string name="hide_templates_title">Ascundeți șabloanele</string>
|
||||
<string name="hide_templates_summary">Șabloanele nu sunt afișate</string>
|
||||
<string name="error_otp_secret_length">Cheia secretă trebuie să conțină cel puțin %1$d caractere.</string>
|
||||
<string name="entry_application_id">ID-ul Aplicației</string>
|
||||
<string name="warning_overwrite_data_title">Suprascrii datele existente?</string>
|
||||
<string name="warning_overwrite_data_description">Această acțiune va înlocui datele existente din intrare, puteți recupera datele vechi dacă istoricul este activat.</string>
|
||||
<string name="credential_provider">Credențialele furnizorului</string>
|
||||
<string name="passkeys_privileged_apps_title">Aplicații privilegiate</string>
|
||||
<string name="passkeys_privileged_apps_summary">Gestionați browserele din lista personalizată de aplicații privilegiate</string>
|
||||
<string name="passkeys_privileged_apps_explanation">AVERTISMENT: O aplicație privilegiată acționează ca o poartă de acces pentru a determina originea unei autentificări. Asigurați-vă că este legitimă pentru a evita probleme de securitate.</string>
|
||||
<string name="passkeys_privileged_apps_ask_title">Aplicație nerecunoscută</string>
|
||||
<string name="passkeys_missing_signature_app_ask_title">Lipsește semnătura</string>
|
||||
<string name="passkeys_auto_select_title">Selectare automată</string>
|
||||
<string name="passkeys_auto_select_summary">Selectare automată dacă există o singură intrare și baza de date este deschisă, doar dacă aplicația solicitantă este compatibilă</string>
|
||||
<string name="passkeys_backup_eligibility_title">Eligibilitate pentru copia de siguranță</string>
|
||||
<string name="passkey_locked_database_description">Selectează ca să deblochezi</string>
|
||||
</resources>
|
||||
|
||||
@@ -93,8 +93,6 @@
|
||||
<string name="list_size_summary">Размер текста элементов списка</string>
|
||||
<string name="loading_database">Загрузка базы…</string>
|
||||
<string name="lowercase">Строчные</string>
|
||||
<string name="hide_password_title">Скрывать пароли</string>
|
||||
<string name="hide_password_summary">Скрывать пароли за (***) по умолчанию</string>
|
||||
<string name="about">О программе</string>
|
||||
<string name="menu_change_key_settings">Изменить главный пароль</string>
|
||||
<string name="settings">Настройки</string>
|
||||
@@ -102,7 +100,6 @@
|
||||
<string name="menu_delete">Удалить</string>
|
||||
<string name="menu_donate">Помочь</string>
|
||||
<string name="menu_edit">Изменить</string>
|
||||
<string name="menu_hide_password">Скрыть пароль</string>
|
||||
<string name="menu_lock">Заблокировать базу</string>
|
||||
<string name="menu_open">Открыть</string>
|
||||
<string name="menu_search">Поиск</string>
|
||||
@@ -181,9 +178,9 @@
|
||||
<string name="menu_appearance_settings">Внешний вид</string>
|
||||
<string name="general">Общие</string>
|
||||
<string name="autofill">Автозаполнение</string>
|
||||
<string name="autofill_sign_in_prompt">Войти с помощью KeePassDX</string>
|
||||
<string name="autofill_sign_in_prompt">Войти с KeePassDX</string>
|
||||
<string name="autofill_explanation_summary">Настройте службу для быстрого заполнения форм в других приложениях</string>
|
||||
<string name="set_credential_provider_service_title">Использовать службу автозаполнения</string>
|
||||
<string name="set_credential_provider_service_title">Служба автозаполнения</string>
|
||||
<string name="password_size_title">Длина создаваемого пароля</string>
|
||||
<string name="password_size_summary">Настройка длины создаваемых паролей по умолчанию</string>
|
||||
<string name="list_password_generator_options_title">Символы пароля</string>
|
||||
|
||||
@@ -83,8 +83,6 @@
|
||||
<string name="list_size_summary">Veľkosť textu v zozname prvkov</string>
|
||||
<string name="loading_database">Načítava sa databáza…</string>
|
||||
<string name="lowercase">Malé písmená</string>
|
||||
<string name="hide_password_title">Skryť heslá</string>
|
||||
<string name="hide_password_summary">Predvolene maskovať heslá (***)</string>
|
||||
<string name="about">O Programe</string>
|
||||
<string name="menu_change_key_settings">Zmeniť hlavný Kľúč</string>
|
||||
<string name="settings">Nastavenia</string>
|
||||
@@ -92,7 +90,6 @@
|
||||
<string name="menu_delete">Zmazať</string>
|
||||
<string name="menu_donate">Darovať</string>
|
||||
<string name="menu_edit">Upraviť</string>
|
||||
<string name="menu_hide_password">Skryť heslo</string>
|
||||
<string name="menu_lock">Zamknúť databázu</string>
|
||||
<string name="menu_open">Otvoriť</string>
|
||||
<string name="menu_search">Hľadať</string>
|
||||
|
||||
@@ -193,8 +193,6 @@
|
||||
<string name="invalid_db_sig">S’u kuptua dot formati i bazës së të dhënave.</string>
|
||||
<string name="keyfile_is_empty">Kartela e kyçit është e zbrazët.</string>
|
||||
<string name="length">Gjatësi</string>
|
||||
<string name="hide_password_title">Fshihi fjalëkalimet</string>
|
||||
<string name="hide_password_summary">Si parazgjedhje, maskoji fjalëkalimet (***)</string>
|
||||
<string name="colorize_password_title">Ngjyrosi fjalëkalimet</string>
|
||||
<string name="list_entries_show_username_title">Shfaq emra përdoruesi</string>
|
||||
<string name="list_groups_show_number_entries_title">Shfaq numër zërash</string>
|
||||
@@ -211,7 +209,6 @@
|
||||
<string name="menu_master_key_settings">Rregullime kyçi të përgjithshëm</string>
|
||||
<string name="menu_copy">Kopjoje</string>
|
||||
<string name="menu_cancel">Anuloje</string>
|
||||
<string name="menu_hide_password">Fshihe fjalëkalimin</string>
|
||||
<string name="menu_lock">Kyçe bazën e të dhënave</string>
|
||||
<string name="menu_save_database">Ruaji të dhënat</string>
|
||||
<string name="menu_reload_database">Ringarko të dhënat</string>
|
||||
|
||||
@@ -255,8 +255,6 @@
|
||||
<string name="passphrase">Дугачка лозинка</string>
|
||||
<string name="invalid_credentials">Није могуће прочитати податке за пријављивање.</string>
|
||||
<string name="invalid_db_same_uuid">%1$s са истим УУИД %2$s већ постоји.</string>
|
||||
<string name="hide_password_title">Сакриј лозинке</string>
|
||||
<string name="hide_password_summary">Подразумевај маскирање лозинки са (***)</string>
|
||||
<string name="colorize_password_title">Обојите лозинке</string>
|
||||
<string name="colorize_password_summary">Обојите знакове лозинке по типу</string>
|
||||
<string name="list_entries_show_username_title">Прикажи корисничка имена</string>
|
||||
@@ -287,7 +285,6 @@
|
||||
<string name="master_key_settings_summary">Промена, обнова</string>
|
||||
<string name="menu_move">Премести</string>
|
||||
<string name="menu_cancel">Откажи</string>
|
||||
<string name="menu_hide_password">Сакриј лозинку</string>
|
||||
<string name="menu_lock">Закључај базу података</string>
|
||||
<string name="menu_save_database">Сачувај податке</string>
|
||||
<string name="menu_merge_database">Обједини податке</string>
|
||||
|
||||
@@ -92,8 +92,6 @@
|
||||
<string name="list_size_summary">Textstorlek i grupplistan</string>
|
||||
<string name="loading_database">Laddar databas…</string>
|
||||
<string name="lowercase">Gemener</string>
|
||||
<string name="hide_password_title">Dölj lösenord</string>
|
||||
<string name="hide_password_summary">Döljer lösenord (***) som standard</string>
|
||||
<string name="about">Om</string>
|
||||
<string name="menu_change_key_settings">Byt huvudnyckel</string>
|
||||
<string name="settings">Inställningar</string>
|
||||
@@ -101,7 +99,6 @@
|
||||
<string name="menu_delete">Radera</string>
|
||||
<string name="menu_donate">Donera</string>
|
||||
<string name="menu_edit">Redigera</string>
|
||||
<string name="menu_hide_password">Dölj lösenord</string>
|
||||
<string name="menu_lock">Lås databas</string>
|
||||
<string name="menu_open">Öppna</string>
|
||||
<string name="menu_search">Sök</string>
|
||||
|
||||
@@ -278,8 +278,6 @@
|
||||
<string name="hint_group_name">குழு பெயர்</string>
|
||||
<string name="invalid_db_same_uuid">அதே uuid %2$s உடன் %1$s ஏற்கனவே உள்ளது.</string>
|
||||
<string name="invalid_db_sig">தரவுத்தள வடிவமைப்பை அடையாளம் காண முடியவில்லை.</string>
|
||||
<string name="hide_password_title">கடவுச்சொற்களை மறைக்கவும்</string>
|
||||
<string name="hide_password_summary">இயல்புநிலையாக கடவுச்சொற்களை (***) மறைக்கவும்</string>
|
||||
<string name="colorize_password_title">கடவுச்சொற்களை வண்ணமயமாக்குங்கள்</string>
|
||||
<string name="colorize_password_summary">தட்டச்சு மூலம் கடவுச்சொல் எழுத்துக்களை வண்ணமயமாக்குங்கள்</string>
|
||||
<string name="list_groups_show_number_entries_summary">ஒரு குழுவில் உள்ளீடுகளின் எண்ணிக்கையைக் காட்டுகிறது</string>
|
||||
@@ -298,7 +296,6 @@
|
||||
<string name="menu_security_settings_summary">குறியாக்கம், முக்கிய வழித்தோன்றல் செயல்பாடு</string>
|
||||
<string name="menu_master_key_settings">முதன்மை விசை அமைப்புகள்</string>
|
||||
<string name="menu_paste">ஒட்டு</string>
|
||||
<string name="menu_hide_password">கடவுச்சொல்லை மறைக்கவும்</string>
|
||||
<string name="menu_merge_database">தேதி செல்கிறது</string>
|
||||
<string name="menu_open_file_read_and_write">மாற்றியமைக்கக்கூடிய</string>
|
||||
<string name="menu_restore_entry_history">வரலாற்றை மீட்டமை</string>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<string name="menu_app_settings">การตั้งค่าแอป</string>
|
||||
<string name="homepage">หน้าหลัก</string>
|
||||
<string name="security">ความปลอดภัย</string>
|
||||
<string name="hide_password_summary">ปิดบังรหัสผ่านเป็น (***) โดยค่าเรื่มต้น</string>
|
||||
<string name="app_timeout_summary">ระยะเวลาที่ไม่ได้ใช้งานก่อนที่จะทำการล็อกฐานข้อมูล</string>
|
||||
<string name="settings">การตั้งค่า</string>
|
||||
<string name="hint_pass">รหัสผ่าน</string>
|
||||
@@ -32,7 +31,6 @@
|
||||
<string name="error_pass_gen_type">จำเป็นต้องเลือกชนิดของรหัสผ่านที่จะสร้างอย่างน้อยหนึ่งอย่าง</string>
|
||||
<string name="generate_password">สร้างรหัสผ่าน</string>
|
||||
<string name="password">รหัสผ่าน</string>
|
||||
<string name="hide_password_title">ซ่อนรหัสผ่าน</string>
|
||||
<string name="hint_conf_pass">ยืนยันรหัสผ่าน</string>
|
||||
<string name="contact">ติดต่อ</string>
|
||||
<string name="select_database_file">เปิดคลังรหัสผ่านที่มีอยู่แล้ว</string>
|
||||
@@ -269,7 +267,6 @@
|
||||
<string name="list_groups_show_number_entries_summary">แสดงจำนวนรายการในกลุ่ม</string>
|
||||
<string name="list_size_title">ขนาดของรายการ</string>
|
||||
<string name="creating_database">กําลังสร้างฐานข้อมูล…</string>
|
||||
<string name="menu_hide_password">ซ่อนรหัสผ่าน</string>
|
||||
<string name="menu_keystore_remove_key">ลบกุญแจปลดล็อกของอุปกรณ์</string>
|
||||
<string name="about">เกี่ยวกับ</string>
|
||||
<string name="menu_move">ย้าย</string>
|
||||
|
||||
@@ -101,8 +101,6 @@
|
||||
<string name="list_size_summary">Öge listesindeki metin boyutu</string>
|
||||
<string name="loading_database">Veri tabanı yükleniyor…</string>
|
||||
<string name="lowercase">Küçük harf</string>
|
||||
<string name="hide_password_title">Parolaları gizle</string>
|
||||
<string name="hide_password_summary">Parolaları öntanımlı olarak (***) ile maskele</string>
|
||||
<string name="about">Hakkında</string>
|
||||
<string name="menu_change_key_settings">Ana anahtarı değiştir</string>
|
||||
<string name="copy_field">%1$s kopyalandı</string>
|
||||
@@ -117,7 +115,6 @@
|
||||
<string name="menu_paste">Yapıştır</string>
|
||||
<string name="menu_delete">Sil</string>
|
||||
<string name="menu_cancel">İptal</string>
|
||||
<string name="menu_hide_password">Parolayı gizle</string>
|
||||
<string name="menu_lock">Veri tabanını kilitle</string>
|
||||
<string name="menu_open">Aç</string>
|
||||
<string name="menu_search">Ara</string>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<string name="menu_showpass">Серсүзне күрсәтү</string>
|
||||
<string name="menu_search">Эзләү</string>
|
||||
<string name="menu_open">Ачу</string>
|
||||
<string name="menu_hide_password">Серсүзне яшерү</string>
|
||||
<string name="menu_move">Күчү</string>
|
||||
<string name="menu_cancel">Баш тарту</string>
|
||||
<string name="menu_delete">Бетерү</string>
|
||||
@@ -27,7 +26,6 @@
|
||||
<string name="settings">Көйләүләр</string>
|
||||
<string name="menu_change_key_settings">Мастер ачкычны үзгәртү</string>
|
||||
<string name="about">Турында</string>
|
||||
<string name="hide_password_title">Серсүзләрне яшерү</string>
|
||||
<string name="list_entries_show_username_title">Кулланучы исемнәрен күрсәтү</string>
|
||||
<string name="password">Серсүз</string>
|
||||
<string name="hint_pass">Серсүз</string>
|
||||
|
||||
@@ -83,8 +83,6 @@
|
||||
<string name="list_size_summary">Розмір тексту у переліку груп</string>
|
||||
<string name="loading_database">Завантаження бази даних…</string>
|
||||
<string name="lowercase">Малі літери</string>
|
||||
<string name="hide_password_title">Ховати паролі</string>
|
||||
<string name="hide_password_summary">Типово ховати паролі за (***)</string>
|
||||
<string name="about">Про KeePassDX</string>
|
||||
<string name="menu_change_key_settings">Змінити головний ключ</string>
|
||||
<string name="settings">Налаштування</string>
|
||||
@@ -92,7 +90,6 @@
|
||||
<string name="menu_delete">Видалити</string>
|
||||
<string name="menu_donate">Підтримати</string>
|
||||
<string name="menu_edit">Змінити</string>
|
||||
<string name="menu_hide_password">Сховати пароль</string>
|
||||
<string name="menu_lock">Заблокувати базу даних</string>
|
||||
<string name="menu_open">Відкрити</string>
|
||||
<string name="menu_search">Пошук</string>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<string name="contribution">Đóng góp</string>
|
||||
<string name="feedback">Phản hồi</string>
|
||||
<string name="homepage">Trang chủ</string>
|
||||
<string name="about_description">Triển khai Android của trình quản lý mật khẩu KeePass</string>
|
||||
<string name="about_description">Phiên bản Android của trình quản lý mật khẩu KeePass.</string>
|
||||
<string name="accept">Chấp nhận</string>
|
||||
<string name="add_entry">Thêm mục</string>
|
||||
<string name="edit_entry">Chỉnh sửa mục</string>
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="encryption_algorithm">Thuật toán mã hóa</string>
|
||||
<string name="key_derivation_function">Hàm dẫn xuất khóa</string>
|
||||
<string name="app_timeout">Hết thời gian</string>
|
||||
<string name="app_timeout_summary">Thời gian rảnh trước khi khóa cơ sở dữ liệu</string>
|
||||
<string name="app_timeout_summary">Thời gian ngưng trước khi khóa cơ sở dữ liệu</string>
|
||||
<string name="application">Ứng dụng</string>
|
||||
<string name="brackets">Dấu ngoặc</string>
|
||||
<string name="extended_ASCII">ASCII mở rộng</string>
|
||||
@@ -43,17 +43,17 @@
|
||||
<string name="clipboard_error_title">Lỗi bảng nhớ tạm</string>
|
||||
<string name="clipboard_error">Một số thiết bị sẽ không cho phép ứng dụng sử dụng bảng nhớ tạm.</string>
|
||||
<string name="clipboard_error_clear">Không thể xóa bảng nhớ tạm</string>
|
||||
<string name="clipboard_timeout">Hết thời gian tạm dừng bảng nhớ tạm</string>
|
||||
<string name="clipboard_timeout">Hết thời gian lưu trong bảng nhớ tạm</string>
|
||||
<string name="clipboard_timeout_summary">Thời lượng lưu trữ trong bảng nhớ tạm (nếu được thiết bị của bạn hỗ trợ)</string>
|
||||
<string name="content_description_background">Nền</string>
|
||||
<string name="content_description_open_file">Mở tệp</string>
|
||||
<string name="content_description_node_children">Nút con</string>
|
||||
<string name="content_description_add_node">Thêm nút</string>
|
||||
<string name="content_description_add_entry">Thêm mục nhập</string>
|
||||
<string name="content_description_add_entry">Thêm mục</string>
|
||||
<string name="content_description_add_group">Thêm nhóm</string>
|
||||
<string name="content_description_add_item">Thêm mục</string>
|
||||
<string name="content_description_file_information">Thông tin tệp</string>
|
||||
<string name="content_description_credentials_information">Thông tin xác thực</string>
|
||||
<string name="content_description_credentials_information">Thông tin đăng nhập</string>
|
||||
<string name="content_description_otp_information">Thông tin mật khẩu một lần</string>
|
||||
<string name="content_description_password_checkbox">Hộp kiểm mật khẩu</string>
|
||||
<string name="content_description_keyfile_checkbox">Hộp kiểm tệp khóa</string>
|
||||
@@ -190,7 +190,7 @@
|
||||
<string name="error_otp_counter">Bộ đếm phải nằm trong khoảng từ %1$d đến %2$d.</string>
|
||||
<string name="error_otp_period">Khoảng thời gian phải nằm trong khoảng từ %1$d đến %2$d giây.</string>
|
||||
<string name="error_otp_digits">Mã thông báo phải chứa %1$d đến %2$d chữ số.</string>
|
||||
<string name="error_otp_type">Loại OTP hiện tại không được biểu mẫu này nhận dạng, quá trình xác thực của nó có thể không tạo ra mã thông báo chính xác nữa.</string>
|
||||
<string name="error_otp_type">Loại OTP hiện tại không thể được nhận dạng bởi biểu mẫu này, nó có khả năng không tạo ra mã thông báo chính xác nữa.</string>
|
||||
<string name="error_string_type">Văn bản này không khớp với mục được yêu cầu.</string>
|
||||
<string name="error_registration_read_only">Không được phép lưu mục mới trong cơ sở dữ liệu chỉ đọc.</string>
|
||||
<string name="error_field_name_already_exists">Tên trường đã tồn tại.</string>
|
||||
@@ -206,7 +206,7 @@
|
||||
<string name="error_no_response_from_challenge">Không thể nhận được phản hồi từ thử thách.</string>
|
||||
<string name="error_cancel_by_user">Đã bị người dùng hủy.</string>
|
||||
<string name="error_driver_required">Cần có trình điều khiển cho %1$s.</string>
|
||||
<string name="error_unable_merge_database_kdb">Không thể hợp nhất từ cơ sở dữ liệu V1.</string>
|
||||
<string name="error_unable_merge_database_kdb">Không thể hợp nhất với cơ sở dữ liệu của tệp kdb.</string>
|
||||
<string name="error_location_unknown">Vị trí cơ sở dữ liệu không xác định, hành động cơ sở dữ liệu không thể được thực hiện.</string>
|
||||
<string name="error_hardware_key_unsupported">Khóa phần cứng không được hỗ trợ.</string>
|
||||
<string name="error_empty_key">Khóa không được để trống.</string>
|
||||
@@ -231,8 +231,6 @@
|
||||
<string name="invalid_db_sig">Không thể nhận dạng được định dạng cơ sở dữ liệu.</string>
|
||||
<string name="keyfile_is_empty">Tệp khóa trống.</string>
|
||||
<string name="length">Chiều dài</string>
|
||||
<string name="hide_password_title">Ẩn mật khẩu</string>
|
||||
<string name="hide_password_summary">Che dấu mật khẩu (***) theo mặc định</string>
|
||||
<string name="colorize_password_title">Tô màu mật khẩu</string>
|
||||
<string name="colorize_password_summary">Tô màu các ký tự mật khẩu theo loại</string>
|
||||
<string name="list_entries_show_username_title">Hiển thị tên người dùng</string>
|
||||
@@ -260,7 +258,7 @@
|
||||
<string name="menu_device_unlock_settings_summary">Sinh trắc học, thông tin xác thực thiết bị</string>
|
||||
<string name="menu_database_settings">Thiết đặt cơ sở dữ liệu</string>
|
||||
<string name="menu_database_settings_summary">Siêu dữ liệu, thùng rác, mẫu, lịch sử</string>
|
||||
<string name="menu_security_settings">Thiết đặt bảo mật</string>
|
||||
<string name="menu_security_settings">Thiết lập bảo mật</string>
|
||||
<string name="menu_security_settings_summary">Mã hóa, hàm dẫn xuất khóa</string>
|
||||
<string name="menu_master_key_settings">Thiết đặt khóa chính</string>
|
||||
<string name="master_key_settings_summary">Thay đổi, gia hạn</string>
|
||||
@@ -271,7 +269,6 @@
|
||||
<string name="menu_paste">Dán</string>
|
||||
<string name="menu_delete">Xóa</string>
|
||||
<string name="menu_cancel">Hủy</string>
|
||||
<string name="menu_hide_password">Ẩn mật khẩu</string>
|
||||
<string name="menu_lock">Khóa cơ sở dữ liệu</string>
|
||||
<string name="menu_save_database">Lưu dữ liệu</string>
|
||||
<string name="menu_merge_database">Hợp nhất dữ liệu</string>
|
||||
@@ -726,4 +723,7 @@
|
||||
<string name="hide_expired_entries_title">Ẩn các mục đã hết hạn</string>
|
||||
<string name="hide_expired_entries_summary">Các mục hết hạn không được hiển thị</string>
|
||||
<string name="warning_database_info_changed_options_read_only">Tải lại cơ sở dữ liệu với những thay đổi mới nhất.</string>
|
||||
<string name="entry_application_id">ID ứng dụng</string>
|
||||
<string name="error_otp_secret_length">Mã bí mật tối thiểu phải có %1$d ký tự.</string>
|
||||
<string name="generate_keyfile">Tạo ra tệp khóa</string>
|
||||
</resources>
|
||||
|
||||
@@ -82,8 +82,6 @@
|
||||
<string name="list_size_summary">列表文字大小</string>
|
||||
<string name="loading_database">正在加载数据库…</string>
|
||||
<string name="lowercase">小写</string>
|
||||
<string name="hide_password_title">隐藏密码</string>
|
||||
<string name="hide_password_summary">默认使用星号(***)隐藏密码</string>
|
||||
<string name="about">关于</string>
|
||||
<string name="menu_change_key_settings">更改主密钥</string>
|
||||
<string name="settings">设置</string>
|
||||
@@ -91,7 +89,6 @@
|
||||
<string name="menu_delete">删除</string>
|
||||
<string name="menu_donate">捐赠</string>
|
||||
<string name="menu_edit">编辑</string>
|
||||
<string name="menu_hide_password">隐藏密码</string>
|
||||
<string name="menu_lock">锁定数据库</string>
|
||||
<string name="menu_open">打开</string>
|
||||
<string name="menu_search">搜索</string>
|
||||
|
||||
@@ -304,8 +304,6 @@
|
||||
<string name="hide_broken_locations_title">隱藏已損壞的資料庫路徑</string>
|
||||
<string name="hide_expired_entries_summary">過期條目將被隱藏</string>
|
||||
<string name="hide_expired_entries_title">隱藏過期的條目</string>
|
||||
<string name="hide_password_summary">預設隱藏密碼</string>
|
||||
<string name="hide_password_title">密碼遮罩</string>
|
||||
<string name="hint_conf_pass">確認密碼</string>
|
||||
<string name="hint_generated_password">生成密碼</string>
|
||||
<string name="hint_group_name">群組名</string>
|
||||
@@ -424,7 +422,6 @@
|
||||
<string name="menu_external_icon">外部圖示</string>
|
||||
<string name="menu_file_selection_read_only">唯讀</string>
|
||||
<string name="menu_form_filling_settings">表格填入</string>
|
||||
<string name="menu_hide_password">隱藏密碼</string>
|
||||
<string name="menu_keystore_remove_key">刪除裝置解鎖密鑰</string>
|
||||
<string name="menu_lock">鎖定資料庫</string>
|
||||
<string name="menu_master_key_settings">主密鑰設定</string>
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
<declare-styleable name="PasswordView">
|
||||
<attr name="passwordHint" format="string" />
|
||||
<attr name="passwordMaxLines" format="integer" />
|
||||
<attr name="passwordVisible" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Specific keyboard attributes -->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user