diff --git a/CHANGELOG b/CHANGELOG
index d1526d50b..5d97ac392 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,14 @@
+KeePassDX(2.5beta31)
+ * Add write permission to keep compatibility with old file managers
+ * Fix autofill for apps
+ * Auto search for autofill
+ * New keyfile input
+ * Icon to hide keyfile input
+ * New lock button
+ * Setting to hide lock button in user interface
+ * Clickable links in notes
+ * Fix autofill for key-value pairs
+
KeePassDX(2.5beta30)
* Fix Lock after screen off (wait 1.5 seconds)
* Upgrade autofill algorithm
diff --git a/app/build.gradle b/app/build.gradle
index 4ed1e26eb..f5ae37673 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
applicationId "com.kunzisoft.keepass"
minSdkVersion 14
targetSdkVersion 29
- versionCode = 30
- versionName = "2.5beta30"
+ versionCode = 31
+ versionName = "2.5RC1"
multiDexEnabled true
testApplicationId = "com.kunzisoft.keepass.tests"
@@ -97,6 +97,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'androidx.biometric:biometric:1.0.1'
+ implementation "androidx.core:core-ktx:1.2.0"
// To upgrade with style
implementation 'com.google.android.material:material:1.0.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e682eb930..cf5fb30a9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,7 +15,6 @@
-
+
-
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt
index 5ab07809f..885d86f32 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.kt
@@ -52,7 +52,6 @@ import com.kunzisoft.keepass.notifications.ClipboardEntryNotificationService
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_ENTRY_HISTORY
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_RESTORE_ENTRY_HISTORY
import com.kunzisoft.keepass.settings.PreferencesUtil
-import com.kunzisoft.keepass.settings.SettingsAutofillActivity
import com.kunzisoft.keepass.tasks.AttachmentFileBinderManager
import com.kunzisoft.keepass.timeout.ClipboardHelper
import com.kunzisoft.keepass.timeout.TimeoutHelper
@@ -73,6 +72,7 @@ class EntryActivity : LockingActivity() {
private var historyView: View? = null
private var entryContentsView: EntryContentsView? = null
private var entryProgress: ProgressBar? = null
+ private var lockView: View? = null
private var toolbar: Toolbar? = null
private var mDatabase: Database? = null
@@ -124,6 +124,11 @@ class EntryActivity : LockingActivity() {
entryContentsView = findViewById(R.id.entry_contents)
entryContentsView?.applyFontVisibilityToFields(PreferencesUtil.fieldFontIsInVisibility(this))
entryProgress = findViewById(R.id.entry_progress)
+ lockView = findViewById(R.id.lock_button)
+
+ lockView?.setOnClickListener {
+ lockAndExit()
+ }
// Init the clipboard helper
clipboardHelper = ClipboardHelper(this)
@@ -148,6 +153,13 @@ class EntryActivity : LockingActivity() {
override fun onResume() {
super.onResume()
+ // Show the lock button
+ lockView?.visibility = if (PreferencesUtil.showLockDatabaseButton(this)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+
// Get Entry from UUID
try {
val keyEntry: NodeId? = intent.getParcelableExtra(KEY_ENTRY)
@@ -462,8 +474,7 @@ class EntryActivity : LockingActivity() {
getString(R.string.entry_user_name)))
},
{
- // Launch autofill settings
- startActivity(Intent(this@EntryActivity, SettingsAutofillActivity::class.java))
+ performedNextEducation(entryActivityEducation, menu)
})
if (!entryCopyEducationPerformed) {
@@ -526,10 +537,6 @@ class EntryActivity : LockingActivity() {
!mReadOnly && mAutoSaveEnable)
}
}
- R.id.menu_lock -> {
- lockAndExit()
- return true
- }
R.id.menu_save_database -> {
mProgressDialogThread?.startDatabaseSave(!mReadOnly)
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt
index 1ea62dcf0..2c8f5af22 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.kt
@@ -81,6 +81,7 @@ class EntryEditActivity : LockingActivity(),
private var entryEditContentsView: EntryEditContentsView? = null
private var entryEditAddToolBar: ActionMenuView? = null
private var saveView: View? = null
+ private var lockView: View? = null
// Education
private var entryEditActivityEducation: EntryEditActivityEducation? = null
@@ -112,6 +113,12 @@ class EntryEditActivity : LockingActivity(),
.show(supportFragmentManager, "DatePickerFragment")
}
}
+
+ lockView = findViewById(R.id.lock_button)
+ lockView?.setOnClickListener {
+ lockAndExit()
+ }
+
// Focus view to reinitialize timeout
resetAppTimeoutWhenViewFocusedOrChanged(entryEditContentsView)
@@ -241,6 +248,16 @@ class EntryEditActivity : LockingActivity(),
}
}
+ override fun onResume() {
+ super.onResume()
+
+ lockView?.visibility = if (PreferencesUtil.showLockDatabaseButton(this)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ }
+
private fun populateViewsWithEntry(newEntry: Entry) {
// Don't start the field reference manager, we want to see the raw ref
mDatabase?.stopManageEntry(newEntry)
@@ -416,10 +433,6 @@ class EntryEditActivity : LockingActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
- R.id.menu_lock -> {
- lockAndExit()
- return true
- }
R.id.menu_save_database -> {
mProgressDialogThread?.startDatabaseSave(!mReadOnly)
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt
index 4d7d0dbf5..6058de700 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/FileDatabaseSelectActivity.kt
@@ -26,13 +26,11 @@ import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
-import android.os.Environment
import android.os.Handler
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
-import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
@@ -48,9 +46,11 @@ import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.adapters.FileDatabaseHistoryAdapter
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.autofill.AutofillHelper
+import com.kunzisoft.keepass.autofill.AutofillHelper.KEY_SEARCH_INFO
import com.kunzisoft.keepass.database.action.ProgressDialogThread
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.education.FileDatabaseSelectActivityEducation
+import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_TASK
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.*
@@ -63,7 +63,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
// Views
private var coordinatorLayout: CoordinatorLayout? = null
- private var fileListContainer: View? = null
+ private var fileManagerExplanationButton: View? = null
private var createButtonView: View? = null
private var openDatabaseButtonView: View? = null
@@ -85,12 +85,16 @@ class FileDatabaseSelectActivity : StylishActivity(),
setContentView(R.layout.activity_file_selection)
coordinatorLayout = findViewById(R.id.activity_file_selection_coordinator_layout)
- fileListContainer = findViewById(R.id.container_file_list)
val toolbar = findViewById(R.id.toolbar)
toolbar.title = ""
setSupportActionBar(toolbar)
+ fileManagerExplanationButton = findViewById(R.id.file_manager_explanation_button)
+ fileManagerExplanationButton?.setOnClickListener {
+ UriUtil.gotoUrl(this, R.string.file_manager_explanation_url)
+ }
+
// Create button
createButtonView = findViewById(R.id.create_database_button)
if (allowCreateDocumentByStorageAccessFramework(packageManager)) {
@@ -105,8 +109,13 @@ class FileDatabaseSelectActivity : StylishActivity(),
createButtonView?.setOnClickListener { createNewFile() }
mOpenFileHelper = OpenFileHelper(this)
- openDatabaseButtonView = findViewById(R.id.open_database_button)
- openDatabaseButtonView?.setOnClickListener(mOpenFileHelper?.openFileOnClickViewListener)
+ openDatabaseButtonView = findViewById(R.id.open_keyfile_button)
+ openDatabaseButtonView?.apply {
+ mOpenFileHelper?.openFileOnClickViewListener?.let {
+ setOnClickListener(it)
+ setOnLongClickListener(it)
+ }
+ }
// History list
val fileDatabaseHistoryRecyclerView = findViewById(R.id.file_list)
@@ -121,7 +130,6 @@ class FileDatabaseSelectActivity : StylishActivity(),
databaseFileUri,
UriUtil.parse(fileDatabaseHistoryEntityToOpen.keyFileUri))
}
- updateFileListVisibility()
}
mAdapterDatabaseHistory?.setOnFileDatabaseHistoryDeleteListener { fileDatabaseHistoryToDelete ->
// Remove from app database
@@ -130,7 +138,6 @@ class FileDatabaseSelectActivity : StylishActivity(),
fileHistoryDeleted?.let { databaseFileHistoryDeleted ->
mAdapterDatabaseHistory?.deleteDatabaseFileHistory(databaseFileHistoryDeleted)
mAdapterDatabaseHistory?.notifyDataSetChanged()
- updateFileListVisibility()
}
}
true
@@ -212,7 +219,8 @@ class FileDatabaseSelectActivity : StylishActivity(),
try {
PasswordActivity.launchForAutofillResult(this@FileDatabaseSelectActivity,
databaseUri, keyFile,
- assistStructure)
+ assistStructure,
+ intent.getParcelableExtra(KEY_SEARCH_INFO))
} catch (e: FileNotFoundException) {
fileNoFoundAction(e)
}
@@ -224,16 +232,21 @@ class FileDatabaseSelectActivity : StylishActivity(),
private fun launchGroupActivity(readOnly: Boolean) {
EntrySelectionHelper.doEntrySelectionAction(intent,
{
- GroupActivity.launch(this@FileDatabaseSelectActivity, readOnly)
+ GroupActivity.launch(this@FileDatabaseSelectActivity,
+ readOnly)
},
{
- GroupActivity.launchForKeyboardSelection(this@FileDatabaseSelectActivity, readOnly)
+ GroupActivity.launchForKeyboardSelection(this@FileDatabaseSelectActivity,
+ readOnly)
// Do not keep history
finish()
},
{ assistStructure ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- GroupActivity.launchForAutofillResult(this@FileDatabaseSelectActivity, assistStructure, readOnly)
+ GroupActivity.launchForAutofillResult(this@FileDatabaseSelectActivity,
+ assistStructure,
+ intent.getParcelableExtra(KEY_SEARCH_INFO),
+ readOnly)
}
})
}
@@ -245,25 +258,6 @@ class FileDatabaseSelectActivity : StylishActivity(),
overridePendingTransition(0, 0)
}
- private fun updateExternalStorageWarning() {
- // To show errors
- var warning = -1
- val state = Environment.getExternalStorageState()
- if (state == Environment.MEDIA_MOUNTED_READ_ONLY) {
- warning = R.string.read_only_warning
- } else if (state != Environment.MEDIA_MOUNTED) {
- warning = R.string.warning_unmounted
- }
-
- val labelWarningView = findViewById(R.id.label_warning)
- if (warning != -1) {
- labelWarningView.setText(warning)
- labelWarningView.visibility = View.VISIBLE
- } else {
- labelWarningView.visibility = View.INVISIBLE
- }
- }
-
override fun onResume() {
val database = Database.getInstance()
if (database.loaded) {
@@ -272,8 +266,6 @@ class FileDatabaseSelectActivity : StylishActivity(),
super.onResume()
- updateExternalStorageWarning()
-
// Construct adapter with listeners
if (PreferencesUtil.showRecentFiles(this)) {
mFileDatabaseHistoryAction?.getAllFileDatabaseHistories { databaseFileHistoryList ->
@@ -289,13 +281,11 @@ class FileDatabaseSelectActivity : StylishActivity(),
true
})
mAdapterDatabaseHistory?.notifyDataSetChanged()
- updateFileListVisibility()
}
}
} else {
mAdapterDatabaseHistory?.clearDatabaseFileHistoryList()
mAdapterDatabaseHistory?.notifyDataSetChanged()
- updateFileListVisibility()
}
// Register progress task
@@ -317,13 +307,6 @@ class FileDatabaseSelectActivity : StylishActivity(),
outState.putParcelable(EXTRA_DATABASE_URI, mDatabaseFileUri)
}
- private fun updateFileListVisibility() {
- if (mAdapterDatabaseHistory?.itemCount == 0)
- fileListContainer?.visibility = View.INVISIBLE
- else
- fileListContainer?.visibility = View.VISIBLE
- }
-
override fun onAssignKeyDialogPositiveClick(
masterPasswordChecked: Boolean, masterPassword: String?,
keyFileChecked: Boolean, keyFile: Uri?) {
@@ -454,10 +437,13 @@ class FileDatabaseSelectActivity : StylishActivity(),
*/
@RequiresApi(api = Build.VERSION_CODES.O)
- fun launchForAutofillResult(activity: Activity, assistStructure: AssistStructure) {
+ fun launchForAutofillResult(activity: Activity,
+ assistStructure: AssistStructure,
+ searchInfo: SearchInfo?) {
AutofillHelper.startActivityForAutofillResult(activity,
Intent(activity, FileDatabaseSelectActivity::class.java),
- assistStructure)
+ assistStructure,
+ searchInfo)
}
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt
index 28a2a397d..8ce18e0a3 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt
@@ -62,6 +62,7 @@ import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.education.GroupActivityEducation
import com.kunzisoft.keepass.icons.assignDatabaseIcon
import com.kunzisoft.keepass.magikeyboard.MagikIME
+import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_COPY_NODES_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_CREATE_GROUP_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_DELETE_NODES_TASK
@@ -89,6 +90,7 @@ class GroupActivity : LockingActivity(),
// Views
private var coordinatorLayout: CoordinatorLayout? = null
+ private var lockView: View? = null
private var toolbar: Toolbar? = null
private var searchTitleView: View? = null
private var toolbarAction: ToolbarAction? = null
@@ -134,6 +136,11 @@ class GroupActivity : LockingActivity(),
groupNameView = findViewById(R.id.group_name)
toolbarAction = findViewById(R.id.toolbar_action)
modeTitleView = findViewById(R.id.mode_title_view)
+ lockView = findViewById(R.id.lock_button)
+
+ lockView?.setOnClickListener {
+ lockAndExit()
+ }
toolbar?.title = ""
setSupportActionBar(toolbar)
@@ -347,7 +354,7 @@ class GroupActivity : LockingActivity(),
// If it's a search
if (Intent.ACTION_SEARCH == intent.action) {
val searchString = intent.getStringExtra(SearchManager.QUERY)?.trim { it <= ' ' } ?: ""
- return mDatabase?.search(searchString)
+ return mDatabase?.createVirtualGroupFromSearch(searchString)
}
// else a real group
else {
@@ -486,7 +493,7 @@ class GroupActivity : LockingActivity(),
// Build response with the entry selected
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && mDatabase != null) {
mDatabase?.let { database ->
- AutofillHelper.buildResponseWhenEntrySelected(this@GroupActivity,
+ AutofillHelper.buildResponse(this@GroupActivity,
entryVersioned.getEntryInfo(database))
}
}
@@ -632,6 +639,13 @@ class GroupActivity : LockingActivity(),
override fun onResume() {
super.onResume()
+
+ // Show the lock button
+ lockView?.visibility = if (PreferencesUtil.showLockDatabaseButton(this)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
// Refresh the elements
assignGroupViewElements()
// Refresh suggestions to change preferences
@@ -753,12 +767,11 @@ class GroupActivity : LockingActivity(),
if (!sortMenuEducationPerformed) {
// lockMenuEducationPerformed
- toolbar != null
- && toolbar!!.findViewById(R.id.menu_lock) != null
- && groupActivityEducation.checkAndPerformedLockMenuEducation(
- toolbar!!.findViewById(R.id.menu_lock),
+ val lockButtonView = findViewById(R.id.lock_button_icon)
+ lockButtonView != null
+ && groupActivityEducation.checkAndPerformedLockMenuEducation(lockButtonView,
{
- onOptionsItemSelected(menu.findItem(R.id.menu_lock))
+ lockAndExit()
},
{
performedNextEducation(groupActivityEducation, menu)
@@ -777,10 +790,6 @@ class GroupActivity : LockingActivity(),
R.id.menu_search ->
//onSearchRequested();
return true
- R.id.menu_lock -> {
- lockAndExit()
- return true
- }
R.id.menu_save_database -> {
mProgressDialogThread?.startDatabaseSave(!mReadOnly)
return true
@@ -956,27 +965,41 @@ class GroupActivity : LockingActivity(),
private const val SEARCH_FRAGMENT_TAG = "SEARCH_FRAGMENT_TAG"
private const val OLD_GROUP_TO_UPDATE_KEY = "OLD_GROUP_TO_UPDATE_KEY"
- private fun buildIntent(context: Context, group: Group?, readOnly: Boolean,
+ private fun buildIntent(context: Context,
+ group: Group?,
+ searchInfo: SearchInfo?,
+ readOnly: Boolean,
intentBuildLauncher: (Intent) -> Unit) {
val intent = Intent(context, GroupActivity::class.java)
if (group != null) {
intent.putExtra(GROUP_ID_KEY, group.nodeId)
}
+ if (searchInfo != null) {
+ intent.action = Intent.ACTION_SEARCH
+ val searchQuery = searchInfo.webDomain ?: searchInfo.applicationId
+ intent.putExtra(SearchManager.QUERY, searchQuery)
+ }
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly)
intentBuildLauncher.invoke(intent)
}
- private fun checkTimeAndBuildIntent(activity: Activity, group: Group?, readOnly: Boolean,
+ private fun checkTimeAndBuildIntent(activity: Activity,
+ group: Group?,
+ searchInfo: SearchInfo?,
+ readOnly: Boolean,
intentBuildLauncher: (Intent) -> Unit) {
if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
- buildIntent(activity, group, readOnly, intentBuildLauncher)
+ buildIntent(activity, group, searchInfo, readOnly, intentBuildLauncher)
}
}
- private fun checkTimeAndBuildIntent(context: Context, group: Group?, readOnly: Boolean,
+ private fun checkTimeAndBuildIntent(context: Context,
+ group: Group?,
+ searchInfo: SearchInfo?,
+ readOnly: Boolean,
intentBuildLauncher: (Intent) -> Unit) {
if (TimeoutHelper.checkTime(context)) {
- buildIntent(context, group, readOnly, intentBuildLauncher)
+ buildIntent(context, group, searchInfo, readOnly, intentBuildLauncher)
}
}
@@ -985,11 +1008,9 @@ class GroupActivity : LockingActivity(),
* Standard Launch
* -------------------------
*/
-
- @JvmOverloads
fun launch(context: Context,
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(context)) {
- checkTimeAndBuildIntent(context, null, readOnly) { intent ->
+ checkTimeAndBuildIntent(context, null, null, readOnly) { intent ->
context.startActivity(intent)
}
}
@@ -1000,10 +1021,9 @@ class GroupActivity : LockingActivity(),
* -------------------------
*/
// TODO implement pre search to directly open the direct group
-
fun launchForKeyboardSelection(context: Context,
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(context)) {
- checkTimeAndBuildIntent(context, null, readOnly) { intent ->
+ checkTimeAndBuildIntent(context, null, null, readOnly) { intent ->
EntrySelectionHelper.startActivityForEntrySelection(context, intent)
}
}
@@ -1013,14 +1033,13 @@ class GroupActivity : LockingActivity(),
* Autofill Launch
* -------------------------
*/
- // TODO implement pre search to directly open the direct group
-
@RequiresApi(api = Build.VERSION_CODES.O)
fun launchForAutofillResult(activity: Activity,
assistStructure: AssistStructure,
+ searchInfo: SearchInfo? = null,
readOnly: Boolean = PreferencesUtil.enableReadOnlyDatabase(activity)) {
- checkTimeAndBuildIntent(activity, null, readOnly) { intent ->
- AutofillHelper.startActivityForAutofillResult(activity, intent, assistStructure)
+ checkTimeAndBuildIntent(activity, null, searchInfo, readOnly) { intent ->
+ AutofillHelper.startActivityForAutofillResult(activity, intent, assistStructure, searchInfo)
}
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt b/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt
index b935f43eb..a28fb059d 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/PasswordActivity.kt
@@ -23,6 +23,7 @@ import android.app.Activity
import android.app.assist.AssistStructure
import android.app.backup.BackupManager
import android.content.Intent
+import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
@@ -32,13 +33,11 @@ import android.text.TextWatcher
import android.util.Log
import android.view.*
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
-import android.widget.Button
-import android.widget.CompoundButton
-import android.widget.EditText
-import android.widget.TextView
+import android.widget.*
import androidx.annotation.RequiresApi
import androidx.appcompat.widget.Toolbar
import androidx.biometric.BiometricManager
+import androidx.core.app.ActivityCompat
import com.google.android.material.snackbar.Snackbar
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.DuplicateUuidDialog
@@ -50,11 +49,13 @@ import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.autofill.AutofillHelper
+import com.kunzisoft.keepass.autofill.AutofillHelper.KEY_SEARCH_INFO
import com.kunzisoft.keepass.biometric.AdvancedUnlockedManager
import com.kunzisoft.keepass.database.action.ProgressDialogThread
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
import com.kunzisoft.keepass.education.PasswordActivityEducation
+import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_LOAD_TASK
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.CIPHER_ENTITY_KEY
import com.kunzisoft.keepass.notifications.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
@@ -66,6 +67,7 @@ import com.kunzisoft.keepass.utils.FileDatabaseInfo
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.UriUtil
import com.kunzisoft.keepass.view.AdvancedUnlockInfoView
+import com.kunzisoft.keepass.view.KeyFileSelectionView
import com.kunzisoft.keepass.view.asError
import kotlinx.android.synthetic.main.activity_password.*
import java.io.FileNotFoundException
@@ -77,7 +79,7 @@ open class PasswordActivity : StylishActivity() {
private var containerView: View? = null
private var filenameView: TextView? = null
private var passwordView: EditText? = null
- private var keyFileView: EditText? = null
+ private var keyFileSelectionView: KeyFileSelectionView? = null
private var confirmButtonView: Button? = null
private var checkboxPasswordView: CompoundButton? = null
private var checkboxKeyFileView: CompoundButton? = null
@@ -92,6 +94,7 @@ open class PasswordActivity : StylishActivity() {
private var mRememberKeyFile: Boolean = false
private var mOpenFileHelper: OpenFileHelper? = null
+ private var mPermissionAsked = false
private var readOnly: Boolean = false
private var mForceReadOnly: Boolean = false
set(value) {
@@ -123,18 +126,23 @@ open class PasswordActivity : StylishActivity() {
confirmButtonView = findViewById(R.id.activity_password_open_button)
filenameView = findViewById(R.id.filename)
passwordView = findViewById(R.id.password)
- keyFileView = findViewById(R.id.pass_keyfile)
+ keyFileSelectionView = findViewById(R.id.keyfile_selection)
checkboxPasswordView = findViewById(R.id.password_checkbox)
checkboxKeyFileView = findViewById(R.id.keyfile_checkox)
checkboxDefaultDatabaseView = findViewById(R.id.default_database)
advancedUnlockInfoView = findViewById(R.id.biometric_info)
infoContainerView = findViewById(R.id.activity_password_info_container)
+ mPermissionAsked = savedInstanceState?.getBoolean(KEY_PERMISSION_ASKED) ?: mPermissionAsked
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrPreference(this, savedInstanceState)
- val browseView = findViewById(R.id.open_database_button)
mOpenFileHelper = OpenFileHelper(this@PasswordActivity)
- browseView.setOnClickListener(mOpenFileHelper!!.openFileOnClickViewListener)
+ keyFileSelectionView?.apply {
+ mOpenFileHelper?.openFileOnClickViewListener?.let {
+ setOnClickListener(it)
+ setOnLongClickListener(it)
+ }
+ }
passwordView?.setOnEditorActionListener(onEditorActionListener)
passwordView?.addTextChangedListener(object : TextWatcher {
@@ -147,17 +155,6 @@ open class PasswordActivity : StylishActivity() {
checkboxPasswordView?.isChecked = true
}
})
- keyFileView?.setOnEditorActionListener(onEditorActionListener)
- keyFileView?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
-
- override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
-
- override fun afterTextChanged(editable: Editable) {
- if (editable.toString().isNotEmpty() && checkboxKeyFileView?.isChecked != true)
- checkboxKeyFileView?.isChecked = true
- }
- })
enableButtonOnCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, _ ->
enableOrNotTheConfirmationButton()
@@ -260,16 +257,38 @@ open class PasswordActivity : StylishActivity() {
private fun launchGroupActivity() {
EntrySelectionHelper.doEntrySelectionAction(intent,
{
- GroupActivity.launch(this@PasswordActivity, readOnly)
+ GroupActivity.launch(this@PasswordActivity,
+ readOnly)
},
{
- GroupActivity.launchForKeyboardSelection(this@PasswordActivity, readOnly)
+ GroupActivity.launchForKeyboardSelection(this@PasswordActivity,
+ readOnly)
// Do not keep history
finish()
},
{ assistStructure ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- GroupActivity.launchForAutofillResult(this@PasswordActivity, assistStructure, readOnly)
+ val searchInfo: SearchInfo? = intent.getParcelableExtra(KEY_SEARCH_INFO)
+ AutofillHelper.checkAutoSearchInfo(this,
+ Database.getInstance(),
+ searchInfo,
+ { items ->
+ // Response is build
+ AutofillHelper.buildResponse(this, items)
+ finish()
+ },
+ {
+ // Here no search info found
+ GroupActivity.launchForAutofillResult(this@PasswordActivity,
+ assistStructure,
+ null,
+ readOnly)
+ },
+ {
+ // Simply close if database not opened, normally not happened
+ finish()
+ }
+ )
}
})
}
@@ -285,11 +304,12 @@ open class PasswordActivity : StylishActivity() {
}
override fun onResume() {
- mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
if (Database.getInstance().loaded)
launchGroupActivity()
+ mRememberKeyFile = PreferencesUtil.rememberKeyFileLocations(this)
+
// If the database isn't accessible make sure to clear the password field, if it
// was saved in the instance state
if (Database.getInstance().loaded) {
@@ -305,6 +325,7 @@ open class PasswordActivity : StylishActivity() {
}
override fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(KEY_PERMISSION_ASKED, mPermissionAsked)
mDatabaseKeyFileUri?.let {
outState.putString(KEY_KEYFILE, it.toString())
}
@@ -319,7 +340,9 @@ open class PasswordActivity : StylishActivity() {
!FileDatabaseInfo(this, it).canWrite
} ?: false
*/
- mForceReadOnly = false
+ mForceReadOnly = mDatabaseFileUri?.let {
+ !FileDatabaseInfo(this, it).exists
+ } ?: true
// Post init uri with KeyFile if needed
if (mRememberKeyFile && (mDatabaseKeyFileUri == null || mDatabaseKeyFileUri.toString().isEmpty())) {
@@ -345,7 +368,7 @@ open class PasswordActivity : StylishActivity() {
// Define Key File text
if (mRememberKeyFile) {
- populateKeyFileTextView(keyFileUri?.toString())
+ populateKeyFileTextView(keyFileUri)
}
// Define listeners for default database checkbox and validate button
@@ -459,13 +482,13 @@ open class PasswordActivity : StylishActivity() {
}
}
- private fun populateKeyFileTextView(text: String?) {
- if (text == null || text.isEmpty()) {
- keyFileView?.setText("")
+ private fun populateKeyFileTextView(uri: Uri?) {
+ if (uri == null || uri.toString().isEmpty()) {
+ keyFileSelectionView?.uri = null
if (checkboxKeyFileView?.isChecked == true)
checkboxKeyFileView?.isChecked = false
} else {
- keyFileView?.setText(text)
+ keyFileSelectionView?.uri = uri
if (checkboxKeyFileView?.isChecked != true)
checkboxKeyFileView?.isChecked = true
}
@@ -486,7 +509,7 @@ open class PasswordActivity : StylishActivity() {
private fun verifyCheckboxesAndLoadDatabase(cipherDatabaseEntity: CipherDatabaseEntity? = null) {
val password: String? = passwordView?.text?.toString()
- val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
+ val keyFile: Uri? = keyFileSelectionView?.uri
verifyCheckboxesAndLoadDatabase(password, keyFile, cipherDatabaseEntity)
}
@@ -499,7 +522,7 @@ open class PasswordActivity : StylishActivity() {
}
private fun verifyKeyFileCheckboxAndLoadDatabase(password: String?) {
- val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
+ val keyFile: Uri? = keyFileSelectionView?.uri
verifyKeyFileCheckbox(keyFile)
loadDatabase(mDatabaseFileUri, password, mDatabaseKeyFileUri)
}
@@ -571,11 +594,42 @@ open class PasswordActivity : StylishActivity() {
super.onCreateOptionsMenu(menu)
- launchEducation(menu)
+ launchEducation(menu) {
+ launchCheckPermission()
+ }
return true
}
+ // Check permission
+ private fun launchCheckPermission() {
+ val writePermission = android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ val permissions = arrayOf(writePermission)
+ if (Build.VERSION.SDK_INT >= 23
+ && !readOnly
+ && !mPermissionAsked) {
+ mPermissionAsked = true
+ // Check self permission to show or not the dialog
+ if (toolbar != null
+ && ActivityCompat.checkSelfPermission(this, writePermission) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions(this, permissions, WRITE_EXTERNAL_STORAGE_REQUEST)
+ }
+ }
+ }
+
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+
+ when (requestCode) {
+ WRITE_EXTERNAL_STORAGE_REQUEST -> {
+ if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE))
+ Toast.makeText(this, R.string.read_only_warning, Toast.LENGTH_LONG).show()
+ }
+ }
+ }
+ }
+
// To fix multiple view education
private var performedEductionInProgress = false
private fun launchEducation(menu: Menu, onEducationFinished: (()-> Unit)? = null) {
@@ -678,7 +732,7 @@ open class PasswordActivity : StylishActivity() {
) { uri ->
if (uri != null) {
mDatabaseKeyFileUri = uri
- populateKeyFileTextView(uri.toString())
+ populateKeyFileTextView(uri)
}
}
}
@@ -703,6 +757,8 @@ open class PasswordActivity : StylishActivity() {
private const val KEY_PASSWORD = "password"
private const val KEY_LAUNCH_IMMEDIATELY = "launchImmediately"
+ private const val KEY_PERMISSION_ASKED = "KEY_PERMISSION_ASKED"
+ private const val WRITE_EXTERNAL_STORAGE_REQUEST = 647
private fun buildAndLaunchIntent(activity: Activity, databaseFile: Uri, keyFile: Uri?,
intentBuildLauncher: (Intent) -> Unit) {
@@ -757,13 +813,15 @@ open class PasswordActivity : StylishActivity() {
activity: Activity,
databaseFile: Uri,
keyFile: Uri?,
- assistStructure: AssistStructure?) {
+ assistStructure: AssistStructure?,
+ searchInfo: SearchInfo?) {
if (assistStructure != null) {
buildAndLaunchIntent(activity, databaseFile, keyFile) { intent ->
AutofillHelper.startActivityForAutofillResult(
activity,
intent,
- assistStructure)
+ assistStructure,
+ searchInfo)
}
} else {
launch(activity, databaseFile, keyFile)
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt
index 1d2eb020d..64aa0d5d5 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/dialogs/AssignMasterKeyDialogFragment.kt
@@ -35,7 +35,7 @@ import android.widget.CompoundButton
import android.widget.TextView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.OpenFileHelper
-import com.kunzisoft.keepass.utils.UriUtil
+import com.kunzisoft.keepass.view.KeyFileSelectionView
class AssignMasterKeyDialogFragment : DialogFragment() {
@@ -51,9 +51,8 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
private var passwordRepeatTextInputLayout: TextInputLayout? = null
private var passwordRepeatView: TextView? = null
- private var keyFileTextInputLayout: TextInputLayout? = null
private var keyFileCheckBox: CompoundButton? = null
- private var keyFileView: TextView? = null
+ private var keyFileSelectionView: KeyFileSelectionView? = null
private var mListener: AssignPasswordDialogListener? = null
@@ -69,16 +68,6 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
}
}
- private val keyFileTextWatcher = object : TextWatcher {
- override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
-
- override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
-
- override fun afterTextChanged(editable: Editable) {
- keyFileCheckBox?.isChecked = true
- }
- }
-
interface AssignPasswordDialogListener {
fun onAssignKeyDialogPositiveClick(masterPasswordChecked: Boolean, masterPassword: String?,
keyFileChecked: Boolean, keyFile: Uri?)
@@ -121,13 +110,14 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
passwordRepeatTextInputLayout = rootView?.findViewById(R.id.password_repeat_input_layout)
passwordRepeatView = rootView?.findViewById(R.id.pass_conf_password)
- keyFileTextInputLayout = rootView?.findViewById(R.id.keyfile_input_layout)
keyFileCheckBox = rootView?.findViewById(R.id.keyfile_checkox)
- keyFileView = rootView?.findViewById(R.id.pass_keyfile)
+ keyFileSelectionView = rootView?.findViewById(R.id.keyfile_selection)
mOpenFileHelper = OpenFileHelper(this)
- rootView?.findViewById(R.id.open_database_button)?.setOnClickListener { view ->
- mOpenFileHelper?.openFileOnClickViewListener?.onClick(view) }
+ keyFileSelectionView?.apply {
+ setOnClickListener(mOpenFileHelper?.openFileOnClickViewListener)
+ setOnLongClickListener(mOpenFileHelper?.openFileOnClickViewListener)
+ }
val dialog = builder.create()
@@ -176,14 +166,12 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
// To check checkboxes if a text is present
passwordView?.addTextChangedListener(passwordTextWatcher)
- keyFileView?.addTextChangedListener(keyFileTextWatcher)
}
override fun onPause() {
super.onPause()
passwordView?.removeTextChangedListener(passwordTextWatcher)
- keyFileView?.removeTextChangedListener(keyFileTextWatcher)
}
private fun verifyPassword(): Boolean {
@@ -216,11 +204,11 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
if (keyFileCheckBox != null
&& keyFileCheckBox!!.isChecked) {
- UriUtil.parse(keyFileView?.text?.toString())?.let { uri ->
+ keyFileSelectionView?.uri?.let { uri ->
mKeyFile = uri
} ?: run {
error = true
- keyFileTextInputLayout?.error = getString(R.string.error_nokeyfile)
+ keyFileSelectionView?.error = getString(R.string.error_nokeyfile)
}
}
return error
@@ -265,8 +253,7 @@ class AssignMasterKeyDialogFragment : DialogFragment() {
) { uri ->
uri?.let { pathUri ->
keyFileCheckBox?.isChecked = true
- keyFileView?.text = pathUri.toString()
-
+ keyFileSelectionView?.uri = pathUri
}
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/helpers/OpenFileHelper.kt b/app/src/main/java/com/kunzisoft/keepass/activities/helpers/OpenFileHelper.kt
index 32bfa7ee6..bfa3b948d 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/helpers/OpenFileHelper.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/helpers/OpenFileHelper.kt
@@ -52,14 +52,22 @@ class OpenFileHelper {
this.fragment = context
}
- inner class OpenFileOnClickViewListener : View.OnClickListener {
+ inner class OpenFileOnClickViewListener : View.OnClickListener, View.OnLongClickListener {
- override fun onClick(v: View) {
+ private fun onAbstractClick(longClick: Boolean = false) {
try {
- try {
- openActivityWithActionOpenDocument()
- } catch(e: Exception) {
- openActivityWithActionGetContent()
+ if (longClick) {
+ try {
+ openActivityWithActionGetContent()
+ } catch (e: Exception) {
+ openActivityWithActionOpenDocument()
+ }
+ } else {
+ try {
+ openActivityWithActionOpenDocument()
+ } catch (e: Exception) {
+ openActivityWithActionGetContent()
+ }
}
} catch (e: Exception) {
Log.e(TAG, "Enable to start the file picker activity", e)
@@ -68,6 +76,15 @@ class OpenFileHelper {
showBrowserDialog()
}
}
+
+ override fun onClick(v: View) {
+ onAbstractClick()
+ }
+
+ override fun onLongClick(v: View?): Boolean {
+ onAbstractClick(true)
+ return true
+ }
}
@SuppressLint("InlinedApi")
diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt
index 306a49f86..e04a024fe 100644
--- a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.kt
@@ -28,8 +28,14 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.database.cursor.EntryCursorKDB
+import com.kunzisoft.keepass.database.cursor.EntryCursorKDBX
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Entry
+import com.kunzisoft.keepass.database.element.Group
+import com.kunzisoft.keepass.database.element.database.DatabaseKDB
+import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
+import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.icons.assignDatabaseIcon
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.view.strikeOut
@@ -69,8 +75,7 @@ class SearchEntryCursorAdapter(private val context: Context,
}
override fun bindView(view: View, context: Context, cursor: Cursor) {
-
- database.getEntryFrom(cursor)?.let { currentEntry ->
+ getEntryFrom(cursor)?.let { currentEntry ->
val viewHolder = view.tag as ViewHolder
// Assign image
@@ -98,14 +103,46 @@ class SearchEntryCursorAdapter(private val context: Context,
}
}
- private class ViewHolder {
- internal var imageViewIcon: ImageView? = null
- internal var textViewTitle: TextView? = null
- internal var textViewSubTitle: TextView? = null
+ private fun getEntryFrom(cursor: Cursor): Entry? {
+ return database.createEntry()?.apply {
+ database.startManageEntry(this)
+ entryKDB?.let { entryKDB ->
+ (cursor as EntryCursorKDB).populateEntry(entryKDB, database.iconFactory)
+ }
+ entryKDBX?.let { entryKDBX ->
+ (cursor as EntryCursorKDBX).populateEntry(entryKDBX, database.iconFactory)
+ }
+ database.stopManageEntry(this)
+ }
}
override fun runQueryOnBackgroundThread(constraint: CharSequence): Cursor? {
- return database.searchEntries(context, constraint.toString())
+ return searchEntries(context, constraint.toString())
+ }
+
+ private fun searchEntries(context: Context, query: String): Cursor? {
+ var cursorKDB: EntryCursorKDB? = null
+ var cursorKDBX: EntryCursorKDBX? = null
+
+ if (database.type == DatabaseKDB.TYPE)
+ cursorKDB = EntryCursorKDB()
+ if (database.type == DatabaseKDBX.TYPE)
+ cursorKDBX = EntryCursorKDBX()
+
+ val searchGroup = database.createVirtualGroupFromSearch(query, SearchHelper.MAX_SEARCH_ENTRY)
+ if (searchGroup != null) {
+ // Search in hide entries but not meta-stream
+ for (entry in searchGroup.getFilteredChildEntries(*Group.ChildFilter.getDefaults(context))) {
+ entry.entryKDB?.let {
+ cursorKDB?.addEntry(it)
+ }
+ entry.entryKDBX?.let {
+ cursorKDBX?.addEntry(it)
+ }
+ }
+ }
+
+ return cursorKDB ?: cursorKDBX
}
fun getEntryFromPosition(position: Int): Entry? {
@@ -113,9 +150,14 @@ class SearchEntryCursorAdapter(private val context: Context,
val cursor = this.cursor
if (cursor.moveToFirst() && cursor.move(position)) {
- pwEntry = database.getEntryFrom(cursor)
+ pwEntry = getEntryFrom(cursor)
}
return pwEntry
}
+ private class ViewHolder {
+ internal var imageViewIcon: ImageView? = null
+ internal var textViewTitle: TextView? = null
+ internal var textViewSubTitle: TextView? = null
+ }
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt
index 06f492206..0ae33b401 100644
--- a/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillHelper.kt
@@ -31,9 +31,17 @@ import android.view.autofill.AutofillManager
import android.view.autofill.AutofillValue
import android.widget.RemoteViews
import androidx.annotation.RequiresApi
+import androidx.core.content.ContextCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.helpers.EntrySelectionHelper
+import com.kunzisoft.keepass.database.element.Database
+import com.kunzisoft.keepass.database.element.icon.IconImage
+import com.kunzisoft.keepass.database.search.SearchHelper
+import com.kunzisoft.keepass.icons.assignDatabaseIcon
import com.kunzisoft.keepass.model.EntryInfo
+import com.kunzisoft.keepass.model.SearchInfo
+import com.kunzisoft.keepass.settings.PreferencesUtil
+import com.kunzisoft.keepass.timeout.TimeoutHelper
@RequiresApi(api = Build.VERSION_CODES.O)
@@ -42,6 +50,7 @@ object AutofillHelper {
private const val AUTOFILL_RESPONSE_REQUEST_CODE = 8165
private const val ASSIST_STRUCTURE = AutofillManager.EXTRA_ASSIST_STRUCTURE
+ const val KEY_SEARCH_INFO = "KEY_SEARCH_INFO"
fun retrieveAssistStructure(intent: Intent?): AssistStructure? {
intent?.let {
@@ -62,11 +71,28 @@ object AutofillHelper {
return ""
}
- private fun buildDataset(context: Context,
- entryInfo: EntryInfo,
- struct: StructureParser.Result): Dataset? {
+ internal fun addHeader(responseBuilder: FillResponse.Builder,
+ packageName: String,
+ webDomain: String?,
+ applicationId: String?) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ if (webDomain != null) {
+ responseBuilder.setHeader(RemoteViews(packageName, R.layout.item_autofill_web_domain).apply {
+ setTextViewText(R.id.autofill_web_domain_text, webDomain)
+ })
+ } else if (applicationId != null) {
+ responseBuilder.setHeader(RemoteViews(packageName, R.layout.item_autofill_app_id).apply {
+ setTextViewText(R.id.autofill_app_id_text, applicationId)
+ })
+ }
+ }
+ }
+
+ internal fun buildDataset(context: Context,
+ entryInfo: EntryInfo,
+ struct: StructureParser.Result): Dataset? {
val title = makeEntryTitle(entryInfo)
- val views = newRemoteViews(context.packageName, title)
+ val views = newRemoteViews(context, title, entryInfo.icon)
val builder = Dataset.Builder(views)
builder.setId(entryInfo.id)
@@ -86,9 +112,16 @@ object AutofillHelper {
}
/**
- * Method to hit when right key is selected
+ * Build the Autofill response for one entry
+ */
+ fun buildResponse(activity: Activity, entryInfo: EntryInfo) {
+ buildResponse(activity, ArrayList().apply { add(entryInfo) })
+ }
+
+ /**
+ * Build the Autofill response for many entry
*/
- fun buildResponseWhenEntrySelected(activity: Activity, entryInfo: EntryInfo) {
+ fun buildResponse(activity: Activity, entriesInfo: List) {
var setResultOk = false
activity.intent?.extras?.let { extras ->
if (extras.containsKey(ASSIST_STRUCTURE)) {
@@ -96,8 +129,9 @@ object AutofillHelper {
StructureParser(structure).parse()?.let { result ->
// New Response
val responseBuilder = FillResponse.Builder()
- val dataset = buildDataset(activity, entryInfo, result)
- responseBuilder.addDataset(dataset)
+ entriesInfo.forEach {
+ responseBuilder.addDataset(buildDataset(activity, it, result))
+ }
val mReplyIntent = Intent()
Log.d(activity.javaClass.name, "Successed Autofill auth.")
mReplyIntent.putExtra(
@@ -115,12 +149,48 @@ object AutofillHelper {
}
}
+ /**
+ * Utility method to perform actions if item is found or not after an auto search in [database]
+ */
+ fun checkAutoSearchInfo(context: Context,
+ database: Database,
+ searchInfo: SearchInfo?,
+ onItemsFound: (items: List) -> Unit,
+ onItemNotFound: () -> Unit,
+ onDatabaseClosed: () -> Unit) {
+ if (database.loaded && TimeoutHelper.checkTime(context)) {
+ var searchWithoutUI = false
+ if (PreferencesUtil.isAutofillAutoSearchEnable(context)
+ && searchInfo != null) {
+ // If search provide results
+ database.createVirtualGroupFromSearch(searchInfo, SearchHelper.MAX_SEARCH_ENTRY)?.let { searchGroup ->
+ if (searchGroup.getNumberOfChildEntries() > 0) {
+ searchWithoutUI = true
+ onItemsFound.invoke(
+ searchGroup.getChildEntriesInfo(database))
+ }
+ }
+ }
+ if (!searchWithoutUI) {
+ onItemNotFound.invoke()
+ }
+ } else {
+ onDatabaseClosed.invoke()
+ }
+ }
+
/**
* Utility method to start an activity with an Autofill for result
*/
- fun startActivityForAutofillResult(activity: Activity, intent: Intent, assistStructure: AssistStructure) {
+ fun startActivityForAutofillResult(activity: Activity,
+ intent: Intent,
+ assistStructure: AssistStructure,
+ searchInfo: SearchInfo?) {
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent)
intent.putExtra(ASSIST_STRUCTURE, assistStructure)
+ searchInfo?.let {
+ intent.putExtra(KEY_SEARCH_INFO, it)
+ }
activity.startActivityForResult(intent, AUTOFILL_RESPONSE_REQUEST_CODE)
}
@@ -139,9 +209,18 @@ object AutofillHelper {
}
}
- private fun newRemoteViews(packageName: String, remoteViewsText: String): RemoteViews {
- val presentation = RemoteViews(packageName, R.layout.item_autofill_service)
- presentation.setTextViewText(R.id.text, remoteViewsText)
+ private fun newRemoteViews(context: Context,
+ remoteViewsText: String,
+ remoteViewsIcon: IconImage? = null): RemoteViews {
+ val presentation = RemoteViews(context.packageName, R.layout.item_autofill_entry)
+ presentation.setTextViewText(R.id.autofill_entry_text, remoteViewsText)
+ if (remoteViewsIcon != null) {
+ presentation.assignDatabaseIcon(context,
+ R.id.autofill_entry_icon,
+ Database.getInstance().drawFactory,
+ remoteViewsIcon,
+ ContextCompat.getColor(context, R.color.green))
+ }
return presentation
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillLauncherActivity.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillLauncherActivity.kt
index 291eda9b1..7f1e749a2 100644
--- a/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillLauncherActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/autofill/AutofillLauncherActivity.kt
@@ -31,7 +31,7 @@ import androidx.appcompat.app.AppCompatActivity
import com.kunzisoft.keepass.activities.FileDatabaseSelectActivity
import com.kunzisoft.keepass.activities.GroupActivity
import com.kunzisoft.keepass.database.element.Database
-import com.kunzisoft.keepass.timeout.TimeoutHelper
+import com.kunzisoft.keepass.model.SearchInfo
@RequiresApi(api = Build.VERSION_CODES.O)
class AutofillLauncherActivity : AppCompatActivity() {
@@ -40,13 +40,31 @@ class AutofillLauncherActivity : AppCompatActivity() {
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
val assistStructure = AutofillHelper.retrieveAssistStructure(intent)
if (assistStructure != null) {
- if (Database.getInstance().loaded && TimeoutHelper.checkTime(this))
- GroupActivity.launchForAutofillResult(this,
- assistStructure)
- else {
- FileDatabaseSelectActivity.launchForAutofillResult(this,
- assistStructure)
+ // Build search param
+ val searchInfo = SearchInfo().apply {
+ applicationId = intent.getStringExtra(KEY_SEARCH_APPLICATION_ID)
+ webDomain = intent.getStringExtra(KEY_SEARCH_DOMAIN)
}
+ // If database is open
+ AutofillHelper.checkAutoSearchInfo(this,
+ Database.getInstance(),
+ searchInfo,
+ { items ->
+ // Items found
+ AutofillHelper.buildResponse(this, items)
+ finish()
+ },
+ {
+ // Show the database UI to select the entry
+ GroupActivity.launchForAutofillResult(this,
+ assistStructure)
+ },
+ {
+ // If database not open
+ FileDatabaseSelectActivity.launchForAutofillResult(this,
+ assistStructure, searchInfo)
+ }
+ )
} else {
setResult(Activity.RESULT_CANCELED)
finish()
@@ -62,10 +80,20 @@ class AutofillLauncherActivity : AppCompatActivity() {
companion object {
- fun getAuthIntentSenderForResponse(context: Context): IntentSender {
- val intent = Intent(context, AutofillLauncherActivity::class.java)
+ private const val KEY_SEARCH_APPLICATION_ID = "KEY_SEARCH_APPLICATION_ID"
+ private const val KEY_SEARCH_DOMAIN = "KEY_SEARCH_DOMAIN"
+
+ fun getAuthIntentSenderForResponse(context: Context,
+ searchInfo: SearchInfo? = null): IntentSender {
return PendingIntent.getActivity(context, 0,
- intent, PendingIntent.FLAG_CANCEL_CURRENT).intentSender
+ // Doesn't work with Parcelable (don't know why?)
+ Intent(context, AutofillLauncherActivity::class.java).apply {
+ searchInfo?.let {
+ putExtra(KEY_SEARCH_APPLICATION_ID, it.applicationId)
+ putExtra(KEY_SEARCH_DOMAIN, it.webDomain)
+ }
+ },
+ PendingIntent.FLAG_CANCEL_CURRENT).intentSender
}
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt
index 789e9a0a3..04007d902 100644
--- a/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/autofill/KeeAutofillService.kt
@@ -22,31 +22,78 @@ package com.kunzisoft.keepass.autofill
import android.os.Build
import android.os.CancellationSignal
import android.service.autofill.*
-import androidx.annotation.RequiresApi
import android.util.Log
import android.widget.RemoteViews
+import androidx.annotation.RequiresApi
import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.database.element.Database
+import com.kunzisoft.keepass.model.SearchInfo
@RequiresApi(api = Build.VERSION_CODES.O)
class KeeAutofillService : AutofillService() {
- override fun onFillRequest(request: FillRequest, cancellationSignal: CancellationSignal,
+ override fun onFillRequest(request: FillRequest,
+ cancellationSignal: CancellationSignal,
callback: FillCallback) {
val fillContexts = request.fillContexts
val latestStructure = fillContexts[fillContexts.size - 1].structure
cancellationSignal.setOnCancelListener { Log.w(TAG, "Cancel autofill.") }
- val responseBuilder = FillResponse.Builder()
// Check user's settings for authenticating Responses and Datasets.
- val parseResult = StructureParser(latestStructure).parse()
- parseResult?.allAutofillIds()?.let { autofillIds ->
+ StructureParser(latestStructure).parse()?.let { parseResult ->
+
+ val searchInfo = SearchInfo().apply {
+ applicationId = parseResult.applicationId
+ webDomain = parseResult.domain
+ }
+
+ AutofillHelper.checkAutoSearchInfo(this,
+ Database.getInstance(),
+ searchInfo,
+ { items ->
+ val responseBuilder = FillResponse.Builder()
+ AutofillHelper.addHeader(responseBuilder, packageName,
+ parseResult.domain, parseResult.applicationId)
+ items.forEach {
+ responseBuilder.addDataset(AutofillHelper.buildDataset(this, it, parseResult))
+ }
+ callback.onSuccess(responseBuilder.build())
+ },
+ {
+ // Show UI if no search result
+ showUIForEntrySelection(parseResult, searchInfo, callback)
+ },
+ {
+ // Show UI if database not open
+ showUIForEntrySelection(parseResult, searchInfo, callback)
+ }
+ )
+ }
+ }
+
+ private fun showUIForEntrySelection(parseResult: StructureParser.Result,
+ searchInfo: SearchInfo,
+ callback: FillCallback) {
+ parseResult.allAutofillIds().let { autofillIds ->
if (autofillIds.isNotEmpty()) {
// If the entire Autofill Response is authenticated, AuthActivity is used
// to generate Response.
- val sender = AutofillLauncherActivity.getAuthIntentSenderForResponse(this)
- val presentation = RemoteViews(packageName, R.layout.item_autofill_service_unlock)
- responseBuilder.setAuthentication(autofillIds, sender, presentation)
+ val sender = AutofillLauncherActivity.getAuthIntentSenderForResponse(this,
+ searchInfo)
+ val responseBuilder = FillResponse.Builder()
+ val remoteViewsUnlock: RemoteViews = if (!parseResult.domain.isNullOrEmpty()) {
+ RemoteViews(packageName, R.layout.item_autofill_unlock_web_domain).apply {
+ setTextViewText(R.id.autofill_web_domain_text, parseResult.domain)
+ }
+ } else if (!parseResult.applicationId.isNullOrEmpty()) {
+ RemoteViews(packageName, R.layout.item_autofill_unlock_app_id).apply {
+ setTextViewText(R.id.autofill_app_id_text, parseResult.applicationId)
+ }
+ } else {
+ RemoteViews(packageName, R.layout.item_autofill_unlock)
+ }
+ responseBuilder.setAuthentication(autofillIds, sender, remoteViewsUnlock)
callback.onSuccess(responseBuilder.build())
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt b/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt
index c22fe810a..601dd184a 100644
--- a/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/autofill/StructureParser.kt
@@ -20,6 +20,7 @@ package com.kunzisoft.keepass.autofill
import android.app.assist.AssistStructure
import android.os.Build
+import android.text.InputType
import androidx.annotation.RequiresApi
import android.util.Log
import android.view.View
@@ -36,47 +37,60 @@ internal class StructureParser(private val structure: AssistStructure) {
private var usernameCandidate: AutofillId? = null
fun parse(): Result? {
- result = Result()
- result?.apply {
- usernameCandidate = null
- mainLoop@ for (i in 0 until structure.windowNodeCount) {
- val windowNode = structure.getWindowNodeAt(i)
- /*
- title.add(windowNode.title)
- windowNode.rootViewNode.webDomain?.let {
- webDomain.add(it)
+ try {
+ result = Result()
+ result?.apply {
+ usernameCandidate = null
+ mainLoop@ for (i in 0 until structure.windowNodeCount) {
+ val windowNode = structure.getWindowNodeAt(i)
+ applicationId = windowNode.title.toString().split("/")[0]
+ Log.d(TAG, "Autofill applicationId: $applicationId")
+
+ if (parseViewNode(windowNode.rootViewNode))
+ break@mainLoop
}
- */
- if (parseViewNode(windowNode.rootViewNode))
- break@mainLoop
+ // If not explicit username field found, add the field just before password field.
+ if (usernameId == null && passwordId != null && usernameCandidate != null)
+ usernameId = usernameCandidate
}
- // If not explicit username field found, add the field just before password field.
- if (usernameId == null && passwordId != null && usernameCandidate != null)
- usernameId = usernameCandidate
- }
- // Return the result only if password field is retrieved
- return if (result?.passwordId != null)
- result
- else
- null
+ // Return the result only if password field is retrieved
+ return if (result?.usernameId != null
+ && result?.passwordId != null)
+ result
+ else
+ null
+ } catch (e: Exception) {
+ return null
+ }
}
private fun parseViewNode(node: AssistStructure.ViewNode): Boolean {
- if (node.autofillId != null) {
- val hints = node.autofillHints
- if (hints != null && hints.isNotEmpty()) {
- if (parseNodeByAutofillHint(node))
+ // Get the domain of a web app
+ node.webDomain?.let {
+ result?.domain = it
+ Log.d(TAG, "Autofill domain: $it")
+ }
+
+ // Only parse visible nodes
+ if (node.visibility == View.VISIBLE) {
+ if (node.autofillId != null
+ && node.autofillType == View.AUTOFILL_TYPE_TEXT) {
+ // Parse methods
+ val hints = node.autofillHints
+ if (hints != null && hints.isNotEmpty()) {
+ if (parseNodeByAutofillHint(node))
+ return true
+ } else if (parseNodeByHtmlAttributes(node))
return true
- } else {
- if (parseNodeByHtmlAttributes(node))
+ else if (parseNodeByAndroidInput(node))
+ return true
+ }
+ // Recursive method to process each node
+ for (i in 0 until node.childCount) {
+ if (parseViewNode(node.getChildAt(i)))
return true
}
- }
- // Recursive method to process each node
- for (i in 0 until node.childCount) {
- if (parseViewNode(node.getChildAt(i)))
- return true
}
return false
}
@@ -85,22 +99,23 @@ internal class StructureParser(private val structure: AssistStructure) {
val autofillId = node.autofillId
node.autofillHints?.forEach {
when {
- it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_USERNAME
- || it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_EMAIL_ADDRESS
- || it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_PHONE -> {
+ it.equals(View.AUTOFILL_HINT_USERNAME, true)
+ || it.equals(View.AUTOFILL_HINT_EMAIL_ADDRESS, true)
+ || it.equals(View.AUTOFILL_HINT_PHONE, true)
+ || it.equals("usernameOrEmail", true)-> {
result?.usernameId = autofillId
Log.d(TAG, "Autofill username hint")
}
- it.toLowerCase(Locale.ENGLISH) == View.AUTOFILL_HINT_PASSWORD
- || it.toLowerCase(Locale.ENGLISH).contains("password") -> {
+ it.equals(View.AUTOFILL_HINT_PASSWORD, true)
+ || it.contains("password", true) -> {
result?.passwordId = autofillId
Log.d(TAG, "Autofill password hint")
return true
}
// Ignore autocomplete="off"
// https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion
- it.toLowerCase(Locale.ENGLISH) == "off" ||
- it.toLowerCase(Locale.ENGLISH) == "on" -> {
+ it.equals("off", true) ||
+ it.equals("on", true) -> {
Log.d(TAG, "Autofill web hint")
return parseNodeByHtmlAttributes(node)
}
@@ -121,15 +136,15 @@ internal class StructureParser(private val structure: AssistStructure) {
when (pairAttribute.second.toLowerCase(Locale.ENGLISH)) {
"tel", "email" -> {
result?.usernameId = autofillId
- Log.d(TAG, "Autofill username type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
+ Log.d(TAG, "Autofill username web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
}
"text" -> {
usernameCandidate = autofillId
- Log.d(TAG, "Autofill type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
+ Log.d(TAG, "Autofill username candidate web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
}
"password" -> {
result?.passwordId = autofillId
- Log.d(TAG, "Autofill password type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
+ Log.d(TAG, "Autofill password web type: ${node.htmlInfo?.tag} ${node.htmlInfo?.attributes}")
return true
}
}
@@ -141,8 +156,57 @@ internal class StructureParser(private val structure: AssistStructure) {
return false
}
+ private fun parseNodeByAndroidInput(node: AssistStructure.ViewNode): Boolean {
+ val autofillId = node.autofillId
+ val inputType = node.inputType
+ if (inputType and InputType.TYPE_CLASS_TEXT != 0) {
+ when {
+ inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS != 0 -> {
+ result?.usernameId = autofillId
+ Log.d(TAG, "Autofill username android type: $inputType")
+ }
+ inputType and InputType.TYPE_TEXT_VARIATION_NORMAL != 0 ||
+ inputType and InputType.TYPE_NUMBER_VARIATION_NORMAL != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_PERSON_NAME != 0 -> {
+ usernameCandidate = autofillId
+ Log.d(TAG, "Autofill username candidate android type: $inputType")
+ }
+ inputType and InputType.TYPE_TEXT_VARIATION_PASSWORD != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD != 0 ||
+ inputType and InputType.TYPE_NUMBER_VARIATION_PASSWORD != 0 -> {
+ result?.passwordId = autofillId
+ Log.d(TAG, "Autofill password android type: $inputType")
+ return true
+ }
+ inputType and InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_FILTER != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_PHONETIC != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_URI != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS != 0 ||
+ inputType and InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD != 0 -> {
+ // Type not used
+ }
+ else -> {
+ Log.d(TAG, "Autofill unknown android type: $inputType")
+ usernameCandidate = autofillId
+ }
+ }
+ }
+ return false
+ }
+
@RequiresApi(api = Build.VERSION_CODES.O)
internal class Result {
+ var applicationId: String? = null
+ var domain: String? = null
+ set(value) {
+ if (field == null)
+ field = value
+ }
+
var usernameId: AutofillId? = null
set(value) {
if (field == null)
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/Database.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/Database.kt
index 2679a326e..7bf122546 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/element/Database.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/element/Database.kt
@@ -20,15 +20,11 @@
package com.kunzisoft.keepass.database.element
import android.content.ContentResolver
-import android.content.Context
import android.content.res.Resources
-import android.database.Cursor
import android.net.Uri
import android.util.Log
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.database.action.node.NodeHandler
-import com.kunzisoft.keepass.database.cursor.EntryCursorKDB
-import com.kunzisoft.keepass.database.cursor.EntryCursorKDBX
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
import com.kunzisoft.keepass.database.element.database.DatabaseKDB
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
@@ -49,6 +45,7 @@ import com.kunzisoft.keepass.database.file.output.DatabaseOutputKDB
import com.kunzisoft.keepass.database.file.output.DatabaseOutputKDBX
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.icons.IconDrawableFactory
+import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.stream.readBytes4ToInt
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.SingletonHolder
@@ -137,6 +134,9 @@ class Database {
val version: String
get() = mDatabaseKDB?.version ?: mDatabaseKDBX?.version ?: "-"
+ val type: Class<*>?
+ get() = mDatabaseKDB?.javaClass ?: mDatabaseKDBX?.javaClass
+
val allowDataCompression: Boolean
get() = mDatabaseKDBX != null
@@ -397,54 +397,17 @@ class Database {
false
}
- @JvmOverloads
- fun search(str: String, max: Int = Integer.MAX_VALUE): Group? {
- return mSearchHelper?.search(this, str, max)
+ fun createVirtualGroupFromSearch(searchQuery: String, max: Int = Integer.MAX_VALUE): Group? {
+ return mSearchHelper?.createVirtualGroupWithSearchResult(this, searchQuery, max)
}
- fun searchEntries(context: Context, query: String): Cursor? {
-
- var cursorKDB: EntryCursorKDB? = null
- var cursorKDBX: EntryCursorKDBX? = null
-
- if (mDatabaseKDB != null)
- cursorKDB = EntryCursorKDB()
- if (mDatabaseKDBX != null)
- cursorKDBX = EntryCursorKDBX()
-
- val searchResult = search(query, SearchHelper.MAX_SEARCH_ENTRY)
- if (searchResult != null) {
- // Search in hide entries but not meta-stream
- for (entry in searchResult.getFilteredChildEntries(*Group.ChildFilter.getDefaults(context))) {
- entry.entryKDB?.let {
- cursorKDB?.addEntry(it)
- }
- entry.entryKDBX?.let {
- cursorKDBX?.addEntry(it)
- }
- }
- }
-
- return cursorKDB ?: cursorKDBX
- }
-
- fun getEntryFrom(cursor: Cursor): Entry? {
- val iconFactory = mDatabaseKDB?.iconFactory ?: mDatabaseKDBX?.iconFactory ?: IconImageFactory()
-
- return createEntry()?.apply {
- startManageEntry(this)
- mDatabaseKDB?.let {
- entryKDB?.let { entryKDB ->
- (cursor as EntryCursorKDB).populateEntry(entryKDB, iconFactory)
- }
- }
- mDatabaseKDBX?.let {
- entryKDBX?.let { entryKDBX ->
- (cursor as EntryCursorKDBX).populateEntry(entryKDBX, iconFactory)
- }
- }
- stopManageEntry(this)
- }
+ fun createVirtualGroupFromSearch(searchInfo: SearchInfo, max: Int = Integer.MAX_VALUE): Group? {
+ val query = (if (searchInfo.webDomain != null)
+ searchInfo.webDomain
+ else
+ searchInfo.applicationId)
+ ?: return null
+ return mSearchHelper?.createVirtualGroupWithSearchResult(this, query, max)
}
@Throws(DatabaseOutputException::class)
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/Entry.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/Entry.kt
index 55c8790fb..9a4edc9d5 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/element/Entry.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/element/Entry.kt
@@ -398,6 +398,7 @@ class Entry : Node, EntryVersionedInterface {
database?.startManageEntry(this)
entryInfo.id = nodeId.toString()
entryInfo.title = title
+ entryInfo.icon = icon
entryInfo.username = username
entryInfo.password = password
entryInfo.url = url
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/Group.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/Group.kt
index 139f3cb28..8606b19f6 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/element/Group.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/element/Group.kt
@@ -28,6 +28,7 @@ import com.kunzisoft.keepass.database.element.group.GroupVersionedInterface
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageStandard
import com.kunzisoft.keepass.database.element.node.*
+import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import java.util.*
import kotlin.collections.ArrayList
@@ -251,6 +252,14 @@ class Group : Node, GroupVersionedInterface {
ArrayList()
}
+ fun getChildEntriesInfo(database: Database): List {
+ val entriesInfo = ArrayList()
+ getChildEntries().forEach { entry ->
+ entriesInfo.add(entry.getEntryInfo(database))
+ }
+ return entriesInfo
+ }
+
fun getFilteredChildEntries(vararg filter: ChildFilter): List {
val withoutMetaStream = filter.contains(ChildFilter.META_STREAM)
val showExpiredEntries = !filter.contains(ChildFilter.EXPIRED)
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt
index 5dbaeac98..21f0c66c2 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt
@@ -26,7 +26,6 @@ import com.kunzisoft.keepass.database.element.entry.EntryKDB
import com.kunzisoft.keepass.database.element.group.GroupKDB
import com.kunzisoft.keepass.database.element.node.NodeIdInt
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
-import com.kunzisoft.keepass.database.element.node.NodeVersioned
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
import com.kunzisoft.keepass.stream.NullOutputStream
import java.io.IOException
@@ -262,6 +261,7 @@ class DatabaseKDB : DatabaseVersioned() {
}
companion object {
+ val TYPE = DatabaseKDB::class.java
const val BACKUP_FOLDER_TITLE = "Backup"
private const val BACKUP_FOLDER_UNDEFINED_ID = -1
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt
index 591ebe481..817e6d09c 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt
@@ -29,7 +29,8 @@ import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters
-import com.kunzisoft.keepass.database.element.*
+import com.kunzisoft.keepass.database.element.DateInstant
+import com.kunzisoft.keepass.database.element.DeletedObject
import com.kunzisoft.keepass.database.element.database.DatabaseKDB.Companion.BACKUP_FOLDER_TITLE
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
import com.kunzisoft.keepass.database.element.group.GroupKDBX
@@ -551,6 +552,7 @@ class DatabaseKDBX : DatabaseVersioned {
}
companion object {
+ val TYPE = DatabaseKDBX::class.java
private val TAG = DatabaseKDBX::class.java.name
private const val DEFAULT_HISTORY_MAX_ITEMS = 10 // -1 unlimited
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/search/SearchHelper.kt b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchHelper.kt
index 929df37cb..5135ca3db 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/search/SearchHelper.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchHelper.kt
@@ -26,7 +26,6 @@ import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.search.iterator.EntrySearchStringIterator
import com.kunzisoft.keepass.database.search.iterator.EntrySearchStringIteratorKDB
import com.kunzisoft.keepass.database.search.iterator.EntrySearchStringIteratorKDBX
-import java.util.*
class SearchHelper(private val isOmitBackup: Boolean) {
@@ -36,22 +35,19 @@ class SearchHelper(private val isOmitBackup: Boolean) {
private var incrementEntry = 0
- fun search(database: Database, qStr: String, max: Int): Group? {
+ fun createVirtualGroupWithSearchResult(database: Database, searchQuery: String, max: Int): Group? {
val searchGroup = database.createGroup()
- searchGroup?.title = "\"" + qStr + "\""
+ searchGroup?.title = "\"" + searchQuery + "\""
// Search all entries
- val loc = Locale.getDefault()
- val finalQStr = qStr.toLowerCase(loc)
-
incrementEntry = 0
database.rootGroup?.doForEachChild(
object : NodeHandler() {
override fun operate(node: Entry): Boolean {
if (incrementEntry >= max)
return false
- if (entryContainsString(node, finalQStr, loc)) {
+ if (entryContainsString(node, searchQuery)) {
searchGroup?.addChildEntry(node)
incrementEntry++
}
@@ -73,7 +69,7 @@ class SearchHelper(private val isOmitBackup: Boolean) {
return searchGroup
}
- private fun entryContainsString(entry: Entry, searchString: String, locale: Locale): Boolean {
+ private fun entryContainsString(entry: Entry, searchString: String): Boolean {
// Entry don't contains string if the search string is empty
if (searchString.isEmpty())
@@ -90,11 +86,10 @@ class SearchHelper(private val isOmitBackup: Boolean) {
iterator?.let {
while (it.hasNext()) {
- val str = it.next()
- if (str.isNotEmpty()) {
- if (str.toLowerCase(locale).contains(searchString)) {
+ val currentString = it.next()
+ if (currentString.isNotEmpty()
+ && currentString.contains(searchString, true)) {
return true
- }
}
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/search/iterator/EntrySearchStringIteratorKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/search/iterator/EntrySearchStringIteratorKDB.kt
index 7510e4b73..a881ea054 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/search/iterator/EntrySearchStringIteratorKDB.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/iterator/EntrySearchStringIteratorKDB.kt
@@ -39,7 +39,7 @@ constructor(private val mEntry: EntryKDB,
title -> mEntry.title
url -> mEntry.url
username -> mEntry.username
- comment -> mEntry.notes
+ notes -> mEntry.notes
else -> ""
}
}
@@ -73,7 +73,7 @@ constructor(private val mEntry: EntryKDB,
title -> mSearchParameters.searchInTitles
url -> mSearchParameters.searchInUrls
username -> mSearchParameters.searchInUserNames
- comment -> mSearchParameters.searchInNotes
+ notes -> mSearchParameters.searchInNotes
else -> true
}
@@ -88,7 +88,7 @@ constructor(private val mEntry: EntryKDB,
private const val title = 0
private const val url = 1
private const val username = 2
- private const val comment = 3
+ private const val notes = 3
private const val maxEntries = 4
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt
index d8a696e98..ac93bc8f9 100644
--- a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.kt
@@ -22,16 +22,16 @@ package com.kunzisoft.keepass.icons
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Resources
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.graphics.Color
+import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
-import androidx.core.content.res.ResourcesCompat
-import androidx.core.widget.ImageViewCompat
import android.util.Log
import android.widget.ImageView
+import android.widget.RemoteViews
+import androidx.core.content.res.ResourcesCompat
+import androidx.core.graphics.drawable.toBitmap
+import androidx.core.widget.ImageViewCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.database.element.icon.IconImageCustom
@@ -70,6 +70,23 @@ class IconDrawableFactory {
}
}
+ /**
+ * Utility method to assign a drawable to a RemoteView and tint it
+ */
+ fun assignDrawableToRemoteViews(superDrawable: SuperDrawable,
+ remoteViews: RemoteViews,
+ imageId: Int,
+ tintColor: Int = Color.BLACK) {
+ val bitmap = superDrawable.drawable.toBitmap()
+ // Tint bitmap if it's not a custom icon
+ if (!superDrawable.custom) {
+ Canvas(bitmap).drawBitmap(bitmap, 0.0F, 0.0F, Paint().apply {
+ colorFilter = PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN)
+ })
+ }
+ remoteViews.setImageViewBitmap(imageId, bitmap)
+ }
+
/**
* Get the [SuperDrawable] [icon] (from cache, or build it and add it to the cache if not exists yet), then [tint] it with [tintColor] if needed
*/
@@ -233,7 +250,6 @@ class IconDrawableFactory {
*/
fun ImageView.assignDefaultDatabaseIcon(iconFactory: IconDrawableFactory, tintColor: Int = Color.WHITE) {
IconPackChooser.getSelectedIconPack(context)?.let { selectedIconPack ->
-
iconFactory.assignDrawableToImageView(
iconFactory.getIconSuperDrawable(context,
selectedIconPack.defaultIconId,
@@ -249,9 +265,10 @@ fun ImageView.assignDefaultDatabaseIcon(iconFactory: IconDrawableFactory, tintCo
/**
* Assign a database [icon] to an ImageView and tint it with [tintColor] if needed
*/
-fun ImageView.assignDatabaseIcon(iconFactory: IconDrawableFactory, icon: IconImage, tintColor: Int = Color.WHITE) {
+fun ImageView.assignDatabaseIcon(iconFactory: IconDrawableFactory,
+ icon: IconImage,
+ tintColor: Int = Color.WHITE) {
IconPackChooser.getSelectedIconPack(context)?.let { selectedIconPack ->
-
iconFactory.assignDrawableToImageView(
iconFactory.getIconSuperDrawable(context,
icon,
@@ -263,3 +280,19 @@ fun ImageView.assignDatabaseIcon(iconFactory: IconDrawableFactory, icon: IconIma
tintColor)
}
}
+
+fun RemoteViews.assignDatabaseIcon(context: Context,
+ imageId: Int,
+ iconFactory: IconDrawableFactory,
+ icon: IconImage,
+ tintColor: Int = Color.BLACK) {
+ iconFactory.assignDrawableToRemoteViews(
+ iconFactory.getIconSuperDrawable(context,
+ icon,
+ 24,
+ true,
+ tintColor),
+ this,
+ imageId,
+ tintColor)
+}
diff --git a/app/src/main/java/com/kunzisoft/keepass/model/EntryInfo.kt b/app/src/main/java/com/kunzisoft/keepass/model/EntryInfo.kt
index a4f4986fc..8edec2238 100644
--- a/app/src/main/java/com/kunzisoft/keepass/model/EntryInfo.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/model/EntryInfo.kt
@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.model
import android.os.Parcel
import android.os.Parcelable
+import com.kunzisoft.keepass.database.element.icon.IconImage
import com.kunzisoft.keepass.otp.OtpElement
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
import java.util.*
@@ -29,6 +30,7 @@ class EntryInfo : Parcelable {
var id: String = ""
var title: String = ""
+ var icon: IconImage? = null
var username: String = ""
var password: String = ""
var url: String = ""
@@ -41,6 +43,7 @@ class EntryInfo : Parcelable {
private constructor(parcel: Parcel) {
id = parcel.readString() ?: id
title = parcel.readString() ?: title
+ icon = parcel.readParcelable(IconImage::class.java.classLoader)
username = parcel.readString() ?: username
password = parcel.readString() ?: password
url = parcel.readString() ?: url
@@ -56,6 +59,7 @@ class EntryInfo : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(id)
parcel.writeString(title)
+ parcel.writeParcelable(icon, flags)
parcel.writeString(username)
parcel.writeString(password)
parcel.writeString(url)
diff --git a/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt b/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt
new file mode 100644
index 000000000..8ad6e99f4
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt
@@ -0,0 +1,42 @@
+package com.kunzisoft.keepass.model
+
+import android.os.Parcel
+import android.os.Parcelable
+
+class SearchInfo : Parcelable {
+
+ var applicationId: String? = null
+ var webDomain: String? = null
+
+ constructor()
+
+ private constructor(parcel: Parcel) {
+ val readAppId = parcel.readString()
+ applicationId = if (readAppId.isNullOrEmpty()) null else readAppId
+ val readDomain = parcel.readString()
+ webDomain = if (readDomain.isNullOrEmpty()) null else readDomain
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeString(applicationId ?: "")
+ parcel.writeString(webDomain ?: "")
+ }
+
+ companion object {
+
+ @JvmField
+ val CREATOR: Parcelable.Creator = object : Parcelable.Creator {
+ override fun createFromParcel(parcel: Parcel): SearchInfo {
+ return SearchInfo(parcel)
+ }
+
+ override fun newArray(size: Int): Array {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt b/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt
index 875f98097..80587a453 100644
--- a/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/otp/OtpEntryFields.kt
@@ -74,7 +74,7 @@ object OtpEntryFields {
// [^&=\s]+=[^&=\s]+(&[^&=\s]+=[^&=\s]+)*
private const val validKeyValue = "[^&=\\s]+"
private const val validKeyValuePair = "$validKeyValue=$validKeyValue"
- private const val validKeyValueRegex = "$validKeyValuePair&($validKeyValuePair)*"
+ private const val validKeyValueRegex = "$validKeyValuePair(&$validKeyValuePair)*"
/**
* Parse fields of an entry to retrieve an OtpElement
@@ -243,21 +243,18 @@ object OtpEntryFields {
val plainText = getField(OTP_FIELD)
if (plainText != null && plainText.isNotEmpty()) {
if (Pattern.matches(validKeyValueRegex, plainText)) {
- try {
+ return try {
// KeeOtp string format
val query = breakDownKeyValuePairs(plainText)
- var secretString = query[SEED_KEY]
- if (secretString == null)
- secretString = ""
- otpElement.setBase32Secret(secretString)
- otpElement.digits = query[DIGITS_KEY]?.toIntOrNull() ?: OTP_DEFAULT_DIGITS
- otpElement.period = query[STEP_KEY]?.toIntOrNull() ?: TOTP_DEFAULT_PERIOD
+ otpElement.setBase32Secret(query[SEED_KEY] ?: "")
+ otpElement.digits = query[DIGITS_KEY]?.toIntOrNull() ?: OTP_DEFAULT_DIGITS
+ otpElement.period = query[STEP_KEY]?.toIntOrNull() ?: TOTP_DEFAULT_PERIOD
- otpElement.type = OtpType.TOTP
- return true
+ otpElement.type = OtpType.TOTP
+ true
} catch (exception: Exception) {
- return false
+ false
}
} else {
// Malformed
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsActivity.kt b/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsActivity.kt
new file mode 100644
index 000000000..8279bf6ad
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsActivity.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 .
+ *
+ */
+package com.kunzisoft.keepass.settings
+
+import android.os.Bundle
+import android.view.MenuItem
+import androidx.appcompat.widget.Toolbar
+import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.activities.stylish.StylishActivity
+
+class AutofillSettingsActivity : StylishActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.activity_toolbar)
+ val toolbar = findViewById(R.id.toolbar)
+ toolbar.setTitle(R.string.autofill_preference_title)
+ setSupportActionBar(toolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+
+ if (savedInstanceState == null) {
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fragment_container, AutofillSettingsFragment())
+ .commit()
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ android.R.id.home -> onBackPressed()
+ }
+
+ return super.onOptionsItemSelected(item)
+ }
+}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/SettingsAutofillActivity.kt b/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt
similarity index 64%
rename from app/src/main/java/com/kunzisoft/keepass/settings/SettingsAutofillActivity.kt
rename to app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt
index 934a785f1..96558b1b4 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/SettingsAutofillActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Jeremy Jamet / Kunzisoft.
+ * Copyright 2020 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
@@ -20,16 +20,14 @@
package com.kunzisoft.keepass.settings
import android.os.Bundle
-import androidx.fragment.app.Fragment
+import androidx.preference.PreferenceFragmentCompat
-class SettingsAutofillActivity : SettingsActivity() {
+import com.kunzisoft.keepass.R
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- mTimeoutEnable = false
- }
+class AutofillSettingsFragment : PreferenceFragmentCompat() {
- override fun retrieveMainFragment(): Fragment {
- return NestedSettingsFragment.newInstance(NestedSettingsFragment.Screen.FORM_FILLING)
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ // Load the preferences from an XML resource
+ setPreferencesFromResource(R.xml.preferences_autofill, rootKey)
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/MagikIMESettings.kt b/app/src/main/java/com/kunzisoft/keepass/settings/MagikeyboardSettingsActivity.kt
similarity index 92%
rename from app/src/main/java/com/kunzisoft/keepass/settings/MagikIMESettings.kt
rename to app/src/main/java/com/kunzisoft/keepass/settings/MagikeyboardSettingsActivity.kt
index 67f8df4cf..98a5ae62a 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/MagikIMESettings.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/MagikeyboardSettingsActivity.kt
@@ -26,7 +26,7 @@ import android.view.MenuItem
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.StylishActivity
-class MagikIMESettings : StylishActivity() {
+class MagikeyboardSettingsActivity : StylishActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -39,7 +39,7 @@ class MagikIMESettings : StylishActivity() {
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
- .replace(R.id.fragment_container, MagikIMESettingsFragment())
+ .replace(R.id.fragment_container, MagikeyboardSettingsFragment())
.commit()
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/MagikIMESettingsFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/MagikeyboardSettingsFragment.kt
similarity index 94%
rename from app/src/main/java/com/kunzisoft/keepass/settings/MagikIMESettingsFragment.kt
rename to app/src/main/java/com/kunzisoft/keepass/settings/MagikeyboardSettingsFragment.kt
index 594c59c28..e087a7a82 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/MagikIMESettingsFragment.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/MagikeyboardSettingsFragment.kt
@@ -24,7 +24,7 @@ import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R
-class MagikIMESettingsFragment : PreferenceFragmentCompat() {
+class MagikeyboardSettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
// Load the preferences from an XML resource
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/MainPreferenceFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/MainPreferenceFragment.kt
index 3f1b0860d..04bdea04a 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/MainPreferenceFragment.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/MainPreferenceFragment.kt
@@ -24,7 +24,6 @@ import android.os.Bundle
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R
-import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
import com.kunzisoft.keepass.database.element.Database
class MainPreferenceFragment : PreferenceFragmentCompat() {
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt
index 6697c541c..2f0e8b4b4 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt
@@ -160,17 +160,22 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
}
findPreference(getString(R.string.magic_keyboard_preference_key))?.setOnPreferenceClickListener {
- startActivity(Intent(context, MagikIMESettings::class.java))
+ startActivity(Intent(context, MagikeyboardSettingsActivity::class.java))
false
}
- findPreference(getString(R.string.clipboard_explanation_key))?.setOnPreferenceClickListener {
- UriUtil.gotoUrl(context!!, R.string.clipboard_explanation_url)
+ findPreference(getString(R.string.autofill_explanation_key))?.setOnPreferenceClickListener {
+ UriUtil.gotoUrl(context!!, R.string.autofill_explanation_url)
false
}
- findPreference(getString(R.string.autofill_explanation_key))?.setOnPreferenceClickListener {
- UriUtil.gotoUrl(context!!, R.string.autofill_explanation_url)
+ findPreference(getString(R.string.settings_autofill_key))?.setOnPreferenceClickListener {
+ startActivity(Intent(context, AutofillSettingsActivity::class.java))
+ false
+ }
+
+ findPreference(getString(R.string.clipboard_explanation_key))?.setOnPreferenceClickListener {
+ UriUtil.gotoUrl(context!!, R.string.clipboard_explanation_url)
false
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/NestedDatabaseSettingsFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/NestedDatabaseSettingsFragment.kt
index bb52f4ca2..cdd94e5ea 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/NestedDatabaseSettingsFragment.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/NestedDatabaseSettingsFragment.kt
@@ -31,7 +31,6 @@ import com.kunzisoft.androidclearchroma.ChromaUtil
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.AssignMasterKeyDialogFragment
import com.kunzisoft.keepass.activities.helpers.ReadOnlyHelper
-import com.kunzisoft.keepass.activities.lock.lock
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
@@ -551,14 +550,10 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
val settingActivity = activity as SettingsActivity?
- when (item.itemId) {
- R.id.menu_lock -> {
- settingActivity?.lock()
- return true
- }
+ return when (item.itemId) {
R.id.menu_save_database -> {
settingActivity?.mProgressDialogThread?.startDatabaseSave(!mDatabaseReadOnly)
- return true
+ true
}
else -> {
@@ -566,7 +561,7 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
settingActivity?.let {
MenuUtil.onDefaultMenuOptionsItemSelected(it, item, mDatabaseReadOnly, true)
}
- return super.onOptionsItemSelected(item)
+ super.onOptionsItemSelected(item)
}
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt
index be7fea957..c3e01fd44 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt
@@ -199,6 +199,12 @@ object PreferencesUtil {
context.resources.getBoolean(R.bool.lock_database_back_root_default))
}
+ fun showLockDatabaseButton(context: Context): Boolean {
+ val prefs = PreferenceManager.getDefaultSharedPreferences(context)
+ return prefs.getBoolean(context.getString(R.string.lock_database_show_button_key),
+ context.resources.getBoolean(R.bool.lock_database_show_button_default))
+ }
+
fun isAutoSaveDatabaseEnabled(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.enable_auto_save_database_key),
@@ -348,4 +354,10 @@ object PreferencesUtil {
return prefs.getBoolean(context.getString(R.string.keyboard_key_sound_key),
context.resources.getBoolean(R.bool.keyboard_key_sound_default))
}
+
+ fun isAutofillAutoSearchEnable(context: Context): Boolean {
+ val prefs = PreferenceManager.getDefaultSharedPreferences(context)
+ return prefs.getBoolean(context.getString(R.string.autofill_auto_search_key),
+ context.resources.getBoolean(R.bool.autofill_auto_search_default))
+ }
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt b/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt
index f2099c35a..b097db221 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/SettingsActivity.kt
@@ -26,6 +26,8 @@ import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.MenuItem
+import android.view.View
+import android.widget.ImageView
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.fragment.app.Fragment
@@ -47,6 +49,7 @@ open class SettingsActivity
private var coordinatorLayout: CoordinatorLayout? = null
private var toolbar: Toolbar? = null
+ private var lockView: View? = null
companion object {
@@ -84,6 +87,11 @@ open class SettingsActivity
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ lockView = findViewById(R.id.lock_button)
+ lockView?.setOnClickListener {
+ lockAndExit()
+ }
+
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, retrieveMainFragment())
@@ -154,6 +162,23 @@ open class SettingsActivity
keyFile: Uri?) {
}
+ private fun hideOrShowLockButton(key: NestedSettingsFragment.Screen) {
+ if (PreferencesUtil.showLockDatabaseButton(this)) {
+ when (key) {
+ NestedSettingsFragment.Screen.DATABASE,
+ NestedSettingsFragment.Screen.DATABASE_MASTER_KEY,
+ NestedSettingsFragment.Screen.DATABASE_SECURITY -> {
+ lockView?.visibility = View.VISIBLE
+ }
+ else -> {
+ lockView?.visibility = View.GONE
+ }
+ }
+ } else {
+ lockView?.visibility = View.GONE
+ }
+ }
+
override fun onBackPressed() {
// this if statement is necessary to navigate through nested and main fragments
if (supportFragmentManager.backStackEntryCount == 0) {
@@ -162,6 +187,7 @@ open class SettingsActivity
supportFragmentManager.popBackStack()
}
toolbar?.setTitle(R.string.settings)
+ hideOrShowLockButton(NestedSettingsFragment.Screen.APPLICATION)
}
private fun replaceFragment(key: NestedSettingsFragment.Screen) {
@@ -173,6 +199,7 @@ open class SettingsActivity
.commit()
toolbar?.title = NestedSettingsFragment.retrieveTitle(resources, key)
+ hideOrShowLockButton(key)
}
override fun onNestedPreferenceSelected(key: NestedSettingsFragment.Screen) {
diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.kt b/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.kt
index 3b8d3f727..16dd0067f 100644
--- a/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryContentsView.kt
@@ -20,6 +20,7 @@ package com.kunzisoft.keepass.view
import android.content.Context
import android.graphics.Color
+import android.text.util.Linkify
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
@@ -71,8 +72,8 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
private val urlContainerView: View
private val urlView: TextView
- private val commentContainerView: View
- private val commentView: TextView
+ private val notesContainerView: View
+ private val notesView: TextView
private val extrasContainerView: View
private val extrasView: ViewGroup
@@ -120,8 +121,8 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
urlContainerView = findViewById(R.id.entry_url_container)
urlView = findViewById(R.id.entry_url)
- commentContainerView = findViewById(R.id.entry_notes_container)
- commentView = findViewById(R.id.entry_notes)
+ notesContainerView = findViewById(R.id.entry_notes_container)
+ notesView = findViewById(R.id.entry_notes)
extrasContainerView = findViewById(R.id.extra_strings_container)
extrasView = findViewById(R.id.extra_strings)
@@ -289,15 +290,17 @@ class EntryContentsView @JvmOverloads constructor(context: Context,
fun assignComment(comment: String?) {
if (comment != null && comment.isNotEmpty()) {
- commentContainerView.visibility = View.VISIBLE
- commentView.apply {
+ notesContainerView.visibility = View.VISIBLE
+ notesView.apply {
text = comment
if (fontInVisibility)
applyFontVisibility()
}
-
+ try {
+ Linkify.addLinks(notesView, Linkify.ALL)
+ } catch (e: Exception) {}
} else {
- commentContainerView.visibility = View.GONE
+ notesContainerView.visibility = View.GONE
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt b/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt
index a80ffa9a2..0773d31ff 100644
--- a/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryEditContentsView.kt
@@ -200,12 +200,16 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
val customFieldsArray = ArrayList()
// Add extra fields from views
entryExtraFieldsContainer.let {
- for (i in 0 until it.childCount) {
- val view = it.getChildAt(i) as EntryEditCustomField
- val key = view.label
- val value = view.value
- val protect = view.isProtected
- customFieldsArray.add(Field(key, ProtectedString(protect, value)))
+ try {
+ for (i in 0 until it.childCount) {
+ val view = it.getChildAt(i) as EntryEditCustomField
+ val key = view.label
+ val value = view.value
+ val protect = view.isProtected
+ customFieldsArray.add(Field(key, ProtectedString(protect, value)))
+ }
+ } catch (exception: Exception) {
+ // Extra field container contains another type of view
}
}
return customFieldsArray
@@ -215,11 +219,14 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
* Add a new view to fill in the information of the customized field and focus it
*/
fun addEmptyCustomField() {
- val entryEditCustomField = EntryEditCustomField(context).apply {
- setFontVisibility(fontInVisibility)
- requestFocus()
+ // Fix current custom field before adding a new one
+ if (isValid()) {
+ val entryEditCustomField = EntryEditCustomField(context).apply {
+ setFontVisibility(fontInVisibility)
+ requestFocus()
+ }
+ entryExtraFieldsContainer.addView(entryEditCustomField)
}
- entryExtraFieldsContainer.addView(entryEditCustomField)
}
/**
@@ -254,26 +261,34 @@ class EntryEditContentsView @JvmOverloads constructor(context: Context,
* @return ErrorValidation An error with a message or a validation without message
*/
fun isValid(): Boolean {
- var isValid = true
-
// Validate password
if (entryPasswordView.text.toString() != entryConfirmationPasswordView.text.toString()) {
entryPasswordLayoutView.error = context.getString(R.string.error_pass_match)
- isValid = false
+ return false
} else {
entryPasswordLayoutView.error = null
}
// Validate extra fields
entryExtraFieldsContainer.let {
- for (i in 0 until it.childCount) {
- val entryEditCustomField = it.getChildAt(i) as EntryEditCustomField
- if (!entryEditCustomField.isValid()) {
- isValid = false
+ try {
+ val customFieldLabelSet = HashSet()
+ for (i in 0 until it.childCount) {
+ val entryEditCustomField = it.getChildAt(i) as EntryEditCustomField
+ if (customFieldLabelSet.contains(entryEditCustomField.label)) {
+ entryEditCustomField.setError(R.string.error_label_exists)
+ return false
+ }
+ customFieldLabelSet.add(entryEditCustomField.label)
+ if (!entryEditCustomField.isValid()) {
+ return false
+ }
}
+ } catch (exception: Exception) {
+ return false
}
}
- return isValid
+ return true
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/kunzisoft/keepass/view/EntryEditCustomField.kt b/app/src/main/java/com/kunzisoft/keepass/view/EntryEditCustomField.kt
index ba3872cc0..b9e9a1bc6 100644
--- a/app/src/main/java/com/kunzisoft/keepass/view/EntryEditCustomField.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/view/EntryEditCustomField.kt
@@ -30,6 +30,7 @@ import android.widget.CompoundButton
import android.widget.EditText
import android.widget.RelativeLayout
import android.widget.TextView
+import androidx.annotation.StringRes
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.security.ProtectedString
@@ -84,14 +85,20 @@ class EntryEditCustomField @JvmOverloads constructor(context: Context,
fun isValid(): Boolean {
// Validate extra field
if (label.isEmpty()) {
- labelLayoutView.error = context.getString(R.string.error_string_key)
+ setError(R.string.error_string_key)
return false
} else {
- labelLayoutView.error = null
+ setError(null)
}
return true
}
+ fun setError(@StringRes errorId: Int?) {
+ labelLayoutView.error = if (errorId == null) null else {
+ context.getString(errorId)
+ }
+ }
+
fun setFontVisibility(applyFontVisibility: Boolean) {
if (applyFontVisibility)
valueView.applyFontVisibility()
diff --git a/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt b/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt
new file mode 100644
index 000000000..26340b98d
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/view/KeyFileSelectionView.kt
@@ -0,0 +1,60 @@
+package com.kunzisoft.keepass.view
+
+import android.content.Context
+import android.net.Uri
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.documentfile.provider.DocumentFile
+import com.google.android.material.textfield.TextInputLayout
+import com.kunzisoft.keepass.R
+
+class KeyFileSelectionView @JvmOverloads constructor(context: Context,
+ attrs: AttributeSet? = null,
+ defStyle: Int = 0)
+ : ConstraintLayout(context, attrs, defStyle) {
+
+ private var mUri: Uri? = null
+
+ private val keyFileNameInputLayout: TextInputLayout
+ private val keyFileNameView: TextView
+ private val keyFileOpenView: ImageView
+
+ init {
+ val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
+ inflater?.inflate(R.layout.view_keyfile_selection, this)
+
+ keyFileNameInputLayout = findViewById(R.id.input_entry_keyfile)
+ keyFileNameView = findViewById(R.id.keyfile_name)
+ keyFileOpenView = findViewById(R.id.keyfile_open_button)
+ }
+
+ override fun setOnClickListener(l: OnClickListener?) {
+ super.setOnClickListener(l)
+ keyFileNameView.setOnClickListener(l)
+ }
+
+ override fun setOnLongClickListener(l: OnLongClickListener?) {
+ super.setOnLongClickListener(l)
+ keyFileNameView.setOnLongClickListener(l)
+ }
+
+ var error: CharSequence?
+ get() = keyFileNameInputLayout.error
+ set(value) {
+ keyFileNameInputLayout.error = value
+ }
+
+ var uri: Uri?
+ get() {
+ return mUri
+ }
+ set(value) {
+ mUri = value
+ keyFileNameView.text = value?.let {
+ DocumentFile.fromSingleUri(context, value)?.name ?: ""
+ } ?: ""
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/color/background_special_button_color.xml b/app/src/main/res/color/background_special_button_color.xml
new file mode 100644
index 000000000..b428a4d71
--- /dev/null
+++ b/app/src/main/res/color/background_special_button_color.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/btn_special_start_bottom_background.xml b/app/src/main/res/drawable-v21/btn_special_start_bottom_background.xml
new file mode 100644
index 000000000..7c5856259
--- /dev/null
+++ b/app/src/main/res/drawable-v21/btn_special_start_bottom_background.xml
@@ -0,0 +1,16 @@
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/btn_special_start_bottom_stroke.xml b/app/src/main/res/drawable-v21/btn_special_start_bottom_stroke.xml
new file mode 100644
index 000000000..db9860cbd
--- /dev/null
+++ b/app/src/main/res/drawable-v21/btn_special_start_bottom_stroke.xml
@@ -0,0 +1,20 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/btn_special_start_bottom_background.xml b/app/src/main/res/drawable/btn_special_start_bottom_background.xml
new file mode 100644
index 000000000..815abdf2d
--- /dev/null
+++ b/app/src/main/res/drawable/btn_special_start_bottom_background.xml
@@ -0,0 +1,34 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/btn_special_start_bottom_stroke.xml b/app/src/main/res/drawable/btn_special_start_bottom_stroke.xml
new file mode 100644
index 000000000..0610c0a85
--- /dev/null
+++ b/app/src/main/res/drawable/btn_special_start_bottom_stroke.xml
@@ -0,0 +1,18 @@
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_apps_white_24dp.xml b/app/src/main/res/drawable/ic_apps_white_24dp.xml
new file mode 100644
index 000000000..373f7752b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_apps_white_24dp.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_web_white_24dp.xml b/app/src/main/res/drawable/ic_web_white_24dp.xml
new file mode 100644
index 000000000..880e42770
--- /dev/null
+++ b/app/src/main/res/drawable/ic_web_white_24dp.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_entry.xml b/app/src/main/res/layout/activity_entry.xml
index 50a14b69a..16f717df0 100644
--- a/app/src/main/res/layout/activity_entry.xml
+++ b/app/src/main/res/layout/activity_entry.xml
@@ -20,6 +20,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_entry_edit.xml b/app/src/main/res/layout/activity_entry_edit.xml
index 103b15fcf..ae6d82ea6 100644
--- a/app/src/main/res/layout/activity_entry_edit.xml
+++ b/app/src/main/res/layout/activity_entry_edit.xml
@@ -102,6 +102,12 @@
+
+
-
-
-
-
+
+
+ app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
+ android:paddingBottom="48dp">
+
-
-
-
-
+
+
-
-
+ android:layout_gravity="center"
+ android:src="@drawable/ic_folder_open_white_24dp"
+ app:tint="?android:attr/textColorHintInverse"
+ android:contentDescription="@string/about"/>
+
-
-
-
+
+
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_group.xml b/app/src/main/res/layout/activity_group.xml
index cd10e56ef..5cfdf3803 100644
--- a/app/src/main/res/layout/activity_group.xml
+++ b/app/src/main/res/layout/activity_group.xml
@@ -140,12 +140,19 @@
android:background="?android:attr/windowBackground" />
+
+
+ app:layout_anchorGravity="end|bottom" />
-
-
-
-
-
-
-
-
+ android:importantForAutofill="no" />
+
@@ -239,7 +214,7 @@
android:paddingEnd="24dp"
android:paddingRight="24dp"
style="@style/KeepassDXStyle.TextAppearance.TinyText"
- android:text="@string/warning_database_read_only"
+ android:text="@string/warning_database_link_revoked"
android:textColor="?attr/textColorInverse"
android:background="?attr/colorAccent"
app:layout_constraintBottom_toTopOf="@+id/activity_password_info_delimiter"
diff --git a/app/src/main/res/layout/activity_toolbar.xml b/app/src/main/res/layout/activity_toolbar.xml
index 38a889f3e..31e6b6f11 100644
--- a/app/src/main/res/layout/activity_toolbar.xml
+++ b/app/src/main/res/layout/activity_toolbar.xml
@@ -17,8 +17,9 @@
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see .
-->
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_list_nodes.xml b/app/src/main/res/layout/fragment_list_nodes.xml
index afd02ca2f..3eef702c8 100644
--- a/app/src/main/res/layout/fragment_list_nodes.xml
+++ b/app/src/main/res/layout/fragment_list_nodes.xml
@@ -44,6 +44,7 @@
diff --git a/app/src/main/res/layout/fragment_set_password.xml b/app/src/main/res/layout/fragment_set_password.xml
index 0f218f34e..5915bec0d 100644
--- a/app/src/main/res/layout/fragment_set_password.xml
+++ b/app/src/main/res/layout/fragment_set_password.xml
@@ -109,44 +109,14 @@
android:layout_height="wrap_content"
android:text="@string/entry_keyfile"/>
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/keyfile_checkox"
+ app:layout_constraintEnd_toEndOf="parent" />
diff --git a/app/src/main/res/layout/item_autofill_app_id.xml b/app/src/main/res/layout/item_autofill_app_id.xml
new file mode 100644
index 000000000..5358ef3dd
--- /dev/null
+++ b/app/src/main/res/layout/item_autofill_app_id.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_autofill_service.xml b/app/src/main/res/layout/item_autofill_entry.xml
similarity index 84%
rename from app/src/main/res/layout/item_autofill_service.xml
rename to app/src/main/res/layout/item_autofill_entry.xml
index bf8cf1632..a7202488b 100644
--- a/app/src/main/res/layout/item_autofill_service.xml
+++ b/app/src/main/res/layout/item_autofill_entry.xml
@@ -22,7 +22,7 @@
android:orientation="horizontal">
+ android:contentDescription="@string/content_description_entry_icon"
+ android:src="@drawable/ic_key_white_24dp" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_autofill_service_unlock.xml b/app/src/main/res/layout/item_autofill_unlock.xml
similarity index 88%
rename from app/src/main/res/layout/item_autofill_service_unlock.xml
rename to app/src/main/res/layout/item_autofill_unlock.xml
index 9ca888b90..9cf3cd995 100644
--- a/app/src/main/res/layout/item_autofill_service_unlock.xml
+++ b/app/src/main/res/layout/item_autofill_unlock.xml
@@ -16,32 +16,27 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_autofill_unlock_app_id.xml b/app/src/main/res/layout/item_autofill_unlock_app_id.xml
new file mode 100644
index 000000000..b9fbfad3b
--- /dev/null
+++ b/app/src/main/res/layout/item_autofill_unlock_app_id.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_autofill_unlock_web_domain.xml b/app/src/main/res/layout/item_autofill_unlock_web_domain.xml
new file mode 100644
index 000000000..973baa9bf
--- /dev/null
+++ b/app/src/main/res/layout/item_autofill_unlock_web_domain.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_autofill_web_domain.xml b/app/src/main/res/layout/item_autofill_web_domain.xml
new file mode 100644
index 000000000..4258b4607
--- /dev/null
+++ b/app/src/main/res/layout/item_autofill_web_domain.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_button_lock.xml b/app/src/main/res/layout/view_button_lock.xml
new file mode 100644
index 000000000..9f3f66162
--- /dev/null
+++ b/app/src/main/res/layout/view_button_lock.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_keyfile_selection.xml b/app/src/main/res/layout/view_keyfile_selection.xml
new file mode 100644
index 000000000..8221ac1b8
--- /dev/null
+++ b/app/src/main/res/layout/view_keyfile_selection.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/database.xml b/app/src/main/res/menu/database.xml
index ac9ff54ed..d94f86817 100644
--- a/app/src/main/res/menu/database.xml
+++ b/app/src/main/res/menu/database.xml
@@ -19,11 +19,6 @@
-->
فتح قاعدة بيانات موجودة
انشاء قاعدة بيانات
- قواعد البيانات الاخيرة
لا تبحثفي مدخلات النسخ الاحتياطي
قيد العمل…
KeePassDX يحتاج صلاحية الكتابة من اجل تعديل قاعدة البيانات.
خوارزمية تشفير جميع البيانات.
قاعدة بيانات غير مدعومة.
- اربط بطاقة الذاكرة لإنشاء او تحميل قاعدة بيانات.
بناء %1$s
تم حفظ كلمة السر المشفرة
قاعدة البيانات لا تمتلك كلمة سر.
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index c9639f291..8606f9aec 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -107,7 +107,6 @@
Mai
Cap resultat de cerca
Sense gestor per aquesta url.
- Obre base de dades recent :
No cerquis entrades a còpia de seguretat ni paperera
Omet els grups \'Còpia de seguretat\' i paperera dels resultats de cerca
Creant nova base de dades…
@@ -128,7 +127,6 @@
Subratllat
Versió de la base de dades no suportada.
Majúscules
- La teva tarja SD no està muntada al teu dispositiu. No podràs carregar ni guardar una base de dades.
Versió %1$s
Introdueix una contrasenya i/o un arxiu clau per desbloquejar la base de dades.
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 2bf19bfad..230ab8476 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -113,7 +113,6 @@
Nikdy
Žádné výsledky hledání
Pro otevření tohoto URL nainstalujte webový prohlížeč.
- Nedávno otevřené databáze
Neprohledávat položky v záloze
Vynechat skupiny „Záloha“ a \"Koš\" z výsledků vyhledávání
Vytvářím novou databázi…
@@ -137,7 +136,6 @@
Nepodporovaná verze databáze.
Velká písmena
Verze %1$s
- Připojit paměťovou kartu pro založení a otevření databáze.
Databázi odemknete zadáním hesla a/nebo souboru s klíčem.
\n
\nNezapomeňte si po každé úpravě zazálohovat kopii svého .kdbx souboru na bezpečné místo.
@@ -197,8 +195,8 @@
Přístup
Varování
Nepoužívejte v hesle pro databázový soubor znaky mimo znakovou sadu Latin-1 (nepoužívejte znaky s diakritikou).
- Opravdu chcete ponechat databázi nechráněnou (bez hesla)?
- Opravdu nechcete používat šifrovací klíč?
+ Pokračovat bez ochrany odemknutím heslem\?
+ Pokračovat bez šifrovacího klíče\?
Biometrická pobídka je zařízením podporována, ale není nastavena.
Otevři biometrickou pobídku k otevření databáze
Šifrované heslo uloženo
@@ -231,7 +229,7 @@
Nechá otevřít databázi snímáním biometrického údaje
Smazat šifrovací klíče
Smazat všechny šifrovací klíče související s biometrickým rozlišením
- Opravdu chcete smazat všechny klíče související s biometrickým rozlišením\?
+ Smazat všechny šifrovací klíče související s biometrickým rozlišením\?
Tuto funkci se nedaří spustit.
Verze %1$s vámi používaného systému Android nevyhovuje minimální verzi %2$s.
Hardware nebyl rozpoznán.
@@ -280,7 +278,7 @@
Propojte své heslo a otisk prstu pro rychlé odemykání databáze.
Upravit položku
Přidejte ke své položce vlastní kolonky. Společná data mohou být sdílena mezi více různými kolonkami.
- Vytvořte k záznamu silné heslo.
+ Vytvořit silné heslo
Vygenerujte silné heslo pro svou položku, definujte je podle kritérií formuláře, a nezapomeňte na bezpečné heslo.
Přidat vlastní kolonky
Registrovat další kolonku, zadat hodnotu a volitelně ji ochránit.
@@ -407,7 +405,7 @@
Nastavení zabezpečení
Nastavení hlavního klíče
Databáze obsahuje duplikátní UUID.
- Prověřením toho dialogu opraví KeePassDX chybu (založením nového UUID pro duplikáty) a bude pokračovat.
+ Opravit chybu založením nového UUID pro duplikáty a pokračovat\?
Databáze otevřena
Kopírujte pole záznamů pomocí schránky Vašeho zařízení
K snadnějšímu otevření databáze použijte pokročilé odemknutí
@@ -433,24 +431,24 @@
Uložit databázi
Vysypat koš
Provádím příkaz…
- Jste si jisti, že chcete natrvalo smazat vybrané uzly\?
+ Natrvalo smazat vybrané uzly\?
Úložiště klíčů není řádně inicializováno.
Zadejte heslo než kliknete na tlačítko biometriky.
Skupina Koš
Uložit databázi automaticky
- Automaticky uloží databázi po důležité akci (pouze v režimu \"Zápis\")
+ Uložit databázi po každé důležité akci (v režimu \"Zápis\")
Připojené soubory
Obnovit historii
Smazat historii
Akce auto-klíče
- Automatická akce klíče Jít po stisknutí klíče Pole
+ Akce klíče \"Jít\" po stisknutí klíče \"Položka\"
Stáhnout %1$s
Zahajuji…
- Probíhá: %1$d%
+ Probíhá: %1$d%
Dokončuji…
Ukončeno! Klepnout pro otevření souboru.
Skrýt propadlé záznamy
- Propadlé záznamy budou skryty
+ Propadlé záznamy jsou skryty
Kontakt
Příspěvky
Feedback
@@ -465,7 +463,14 @@
Skrýt špatné odkazy na databáze
Skrýt špatné odkazy v seznamu nedávných databází
Udělit právo zápisu pro uložení změn v databázi
- KeePassDX © %1$d Kunzisoft je <strong>otevřený software</strong> a <strong>bey reklam</strong>.
+ KeePassDX © %1$d Kunzisoft je <strong>svobodný software</strong> a <strong>bey reklam</strong>.
\nJe poskytován jak je, pod licencí <strong>GPLv3</strong>, bez jakékoli záruky.
Abychom si <strong>udrželi svoji svobodu</strong>, <strong>opravili chyby</strong>,<strong>doplnili funkce</strong> a <strong>byli vždy aktivní</strong>, počítáme s Vaším <strong>přispěním</strong>.
+ Nedaří se vytvořit soubor s databází.
+ Přidat přílohu
+ Zahodit
+ Zahodit změny\?
+ Ověřit
+ Nastavit správu One-Time hesla (HOTP / TOTP) pro založení tokenu požadovaného pro dvoufázové ověření (2FA).
+ Nastavit OTP
\ No newline at end of file
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 0a954c1ca..7ee233c87 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -112,7 +112,6 @@
Aldrig
Ingen søgeresultater
Installer en web-browser til at åbne URL.
- Seneste databaser
Gennemsøg ikke backup poster
Udelader \"Sikkerhedskopiering\" og \"Papirkurv\" - grupper fra søgeresultater
Opretter ny database…
@@ -135,7 +134,6 @@
Understregning
Database-versionen er ikke understøttet.
Store bogstaver
- Monter hukommelseskortet for at oprette eller indlæse en database.
Version %1$s
Angiv en adgangskode og/eller en nøglefil til at låse databasen op.
\n
@@ -197,7 +195,7 @@
Advarsel
Undgå adgangskodetegn uden for tekstkodningsformatet i databasefilen (ukendte tegn konverteres til samme bogstav).
Bekræft brug af ingen adgangskode til beskyttelse mod oplåsning\?
- Bekræft ingen brug af en krypteringsnøgle?
+ Fortsæt uden krypteringsnøgle\?
Biometrisk prompt understøttes, men er ikke konfigureret.
Åbn den biometriske prompt for at låse databasen op
Krypteret adgangskode er gemt
@@ -230,7 +228,7 @@
Lader dig scanne din biometrisk for at åbne databasen
Slet krypteringsnøgler
Slet alle krypteringsnøgler, der er relateret til fingeraftryk
- Bekræft sletning af alle nøgler, der er relateret til fingeraftryksgenkendelse\?
+ Slet alle nøgler, der er relateret til fingeraftryksgenkendelse\?
Funktionen kunne ikke startes.
Android-version %1$s opfylder ikke minimum versionskrav %2$s.
Kunne ikke finde den tilsvarende hardware.
@@ -279,7 +277,7 @@
Link adgangskoden til det scannede fingeraftryk for hurtigt at låse databasen op.
Rediger posten
Rediger post med brugerdefinerede felter. Pool data kan refereres mellem forskellige indtastningsfelter.
- Opret en stærk adgangskode til posten.
+ Opret en stærk adgangskode
Generer en stærk kodeord til at forbinde elementet, definer det i henhold til kriteriet for formularen og glem ikke et sikkert kodeord.
Tilføj brugerdefinerede felter
Registrer et ekstra felt, tilføj en værdi og beskyt det eventuelt.
@@ -323,7 +321,7 @@
Magikeyboard (KeePassDX)
Magikeyboard indstillinger
Post
- Timeout
+ Udløbstid
Meddelelsesinfo
Vis en meddelelse, når en post er til rådighed
Post
@@ -375,7 +373,7 @@
Kan ikke oprette database med denne adgangskode og nøglefil.
Avanceret oplåsning
Gem biometrisk genkendelse
- ADVARSEL: Brug af biometrisk genkendelse fritager ikke for at kende hovedadgangskode.
+ Advarsel: hovedadgangskoden skal stadig huskes, hvis der bruges biometrisk genkendelse.
Åbn database med biometrisk genkendelse
Uddrag databasens legitimationsoplysninger med biometriske data
Biometrisk
@@ -406,7 +404,7 @@
Sikkerhedsindstillinger
Indstillinger for hovednøgle
Databasen indeholder dublerede UUID\'er.
- Ved at godkende dialogboksen, vil KeePassDX løse problemet (ved at generere nye UUID\'er for dubletter) og fortsætte.
+ Løs problemet ved at generere nye UUID\'er for dubletter til at fortsætte\?
Database åbnet
Kopier indtastningsfelter ved hjælp af enhedens udklipsholder
Brug avanceret oplåsning for at gøre det lettere at åbne en database
@@ -432,12 +430,12 @@
Gem database
Tøm papirkurven
Udfører kommandoen…
- Bekræft sletning ad de markerede noder permanent\?
+ Slet markerede noder permanent\?
Nøglelageret er ikke korrekt initialiseret.
Skriv adgangskoden, før der klikkes på den biometriske knap.
Papirkurvsgruppe
Gem automatisk database
- Gem automatisk databasen efter en vigtig handling (kun i tilstanden \"Modificerbar\")
+ Gem databasen efter hver en vigtig handling (i tilstanden \"Modificerbar\")
Vedhæftninger
Gendan historik
Slet historik
@@ -445,11 +443,11 @@
Handling af Gå-tasten udføres automatisk, efter der er trykket på en Felt nøgle
Hent %1$s
Initialiserer…
- I gang: %1$d%
+ I gang: %1$d%
Færdiggørelse…
Komplet! Tryk for at åbne filen.
Skjul udløbne poster
- Udløbne poster vil blive skjult
+ Udløbne poster er skjult
Kontakt
Bidrag
Tilbagemelding
@@ -467,4 +465,11 @@
Skjule brudte databaselinks
Skjul brudte links på listen over seneste databaser
Giv fil skriveadgang for at gemme databasændringer
+ Opsætning af engangsadgangskodestyring (HOTP / TOTP) for at generere et token anmodet om tofaktorautentisering (2FA).
+ Opsætning af OTP
+ Databasefilen kunne ikke oprettes.
+ Tilføj vedhæng
+ Kassér
+ Kasser ændringer\?
+ Valider
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index a8e1f7a95..43b92a40d 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -20,8 +20,11 @@
Translations from BoDEAN
Translations from Matthias Dill
Translations from David Ramiro
--->
- Feedback
+-->
+
+ Kontakt
+ Mitwirken
+ Rückmeldung
Webseite
Android-Implementierung des Passwortmanagers KeePass
Akzeptieren
@@ -42,12 +45,13 @@
Zwischenablage-Timeout
Dauer der Speicherung in der Zwischenablage
%1$s in die Zwischenablage kopieren
- Datenbank-Schlüsseldatei erzeugen …
+ Datenbank-Schlüsseldatei erzeugen…
Datenbank
- Entschlüsselung der Datenbankinhalte …
+ Entschlüsselung der Datenbankinhalte…
Als Standard-Datenbank verwenden
Zahlen
- KeePassDX © %1$d Kunzisoft. Alle Rechte vorbehalten. Die Nutzung der Software erfolgt auf eigene Verantwortung und ohne jegliche Garantie. Die Applikation ist frei und wird unter den Bedingungen der GNU GPL Version 3 (oder später) verbreitet und lizenziert.
+ KeePassDX © %1$d Kunzisoft ist <strong>quelloffen</strong> und <strong>ohne Werbung</strong>.\nDie Nutzung der Software erfolgt auf eigene Verantwortung und ohne jegliche Garantie. Die Applikation wird unter den Bedingungen der <strong>GPLv3</strong> lizenziert.
+ Damit wir <strong>unsere Unabhängigkeit erhalten</strong>, <strong>Fehler korrigieren</strong>, <strong>Funktionen hinzufügen</strong> und <strong>weiterhin aktiv bleiben</strong> können, zählen wir auf Ihren <strong>Beitrag</strong>.
Vorhandene Datenbank öffnen
Letzter Zugriff
Abbrechen
@@ -97,7 +101,7 @@
Länge
Größe der Listenelemente
Schriftgröße der Listenelemente
- Datenbank wird geladen …
+ Datenbank wird geladen…
Kleinbuchstaben
Passwort verstecken
Passwörter standardmäßig mit (***) maskieren
@@ -118,11 +122,12 @@
Nie
Keine Suchergebnisse
Bitte einen Webbrowser installieren, um diese URL zu öffnen.
- Zuletzt geöffnete Datenbanken
Papierkorb/Sicherungen nicht durchsuchen
Die Gruppen „Sicherung“ und „Papierkorb“ werden bei der Suche nicht berücksichtigt
- Neue Datenbank anlegen …
- Ausführen …
+ Schnellsuche
+ Beim Öffnen einer Datenbank eine Suche veranlassen
+ Neue Datenbank anlegen…
+ Ausführen…
Sicherheit
Schreibgeschützt
KeePassDX benötigt Schreibrechte, um etwas an der Datenbank zu ändern.
@@ -131,7 +136,7 @@
Start
Schlüsseltransformationen
Zusätzliche Schlüsseltransformationen bieten einen besseren Schutz gegen Wörterbuch- oder Brute-Force-Angriffe. Allerdings dauert dann auch das Laden und Speichern der Datenbank entsprechend länger.
- Datenbank wird gespeichert …
+ Datenbank wird gespeichert…
Leerzeichen
Suchen
Natürliche Sortierung
@@ -144,7 +149,6 @@
Großbuchstaben
Warnung
Passwortzeichen in der Datenbank vermeiden, die kein Text-Encoding-Format besitzen (nicht erkannte Zeichen werden in denselben Buchstaben umgewandelt).
- Die Speicher einbinden, um eine Datenbank erstellen oder laden zu können.
Version %1$s
Geben Sie das Passwort und/oder die Schlüsseldatei ein, um Ihre Datenbank zu entsperren.
\n
@@ -175,7 +179,6 @@
Bildschirmsperre
Datenbank sperren, wenn der Bildschirm ausgeschaltet wird
Neue Datenbank erstellen
- App-Design
Hauptschlüssel zuweisen
Pfad
Dateiname
@@ -195,7 +198,6 @@
Allgemein
Biometrische Abfrage öffnen, um Anmeldedaten zu speichern.
Diese Datenbank hat noch kein Passwort.
- App-Design, das in der App genutzt wird
Verschlüsselung
Schlüsselableitungsfunktion
Erweiterte ASCII
@@ -266,7 +268,7 @@
Verknüpft Ihr Passwort mit Ihrer gescannten Biometrie, um Ihre Datenbank schnell zu entsperren.
Eintrag bearbeiten
Bearbeiten Sie Ihren Eintrag mit persönlichen Feldern. Persönliche Felder können mit Querverweisen aus anderen Einträgen ergänzt werden.
- Ein starkes Passwort für den Eintrag erstellen.
+ Ein starkes Passwort erstellen
Erzeugung eines starken Passworts, das mit dem Eintrag verknüpft wird, nach Kriterien, die einfach in einem Formular festgelegt werden. Dabei an die Passwortsicherheit denken.
Benutzerdefinierte Felder hinzufügen
Tragen Sie ein zusätzliches Feld ein, fügen Sie einen Wert hinzu und schützen Sie es optional.
@@ -281,7 +283,7 @@
Auswählen, wie Einträge und Gruppen sortiert werden.
Mitmachen
Mithelfen, um Stabilität und Sicherheit zu verbessern und weitere Funktionen zu ermöglichen.
- Anders als viele andere Passwortmanager ist dieser <strong>werbefrei</strong>, <strong>quelloffen</strong> und unter Copyleft lizenziert. <strong>Es werden keine persönlichen Daten gesammelt</strong>, in welcher Form auch immer, egal welche Version (kostenlos oder pro) Sie verwenden.
+ Anders als viele andere Passwortmanager ist dieser <strong>werbefrei</strong>, <strong>quelloffen</strong> und unter <strong>Copyleft lizenziert</strong>. Es werden keine persönlichen Daten gesammelt, in welcher Form auch immer, egal welche Version (kostenlos oder pro) Sie verwenden.
Mit dem Kauf der Pro-Version erhält man Zugang zu dieser <strong>visuellen Funktion</strong> und unterstützt insbesondere <strong>die Umsetzung gemeinschaftlicher Projektarbeiten.</strong>
Dieser <strong>visuelle Stil</strong> wurde wegen Ihrer Großzügigkeit freigeschaltet.
Um unsere Freiheit zu bewahren und immer aktiv zu bleiben, zählen wir auf Ihren <strong>Beitrag.</strong>
@@ -297,8 +299,8 @@
ChaCha20
AES
Argon2
- Symbolepaket
- In der App verwendetes Symbolepaket
+ Symbolpaket
+ In der App verwendetes Symbolpaket
Eine Gruppe kann nicht in sich selbst verschoben werden.
Kopieren
Verschieben
@@ -344,7 +346,15 @@
Vibrierende Tastendrücke
Hörbare Tastendrücke
Auswahlmodus
- Nicht die App beenden …
+ Speicherort der Datenbanken
+ Speicherort der Datenbanken merken
+ Speicherort der Schlüsseldateien
+ Speicherort der Schlüssel zu Datenbanken merken
+ Zuletzt verwendete Dateien anzeigen
+ Speicherort zuletzt verwendeter Datenbanken anzeigen
+ Defekte Datenbankverknüpfungen ausblenden
+ Nicht funktionierende Verknüpfungen in der Liste der zuletzt verwendeten Datenbanken ausblenden
+ Nicht die App beenden…
Datenbank sperren, wenn auf dem Hauptbildschirm der Zurück-Button gedrückt wird
Beim Schließen löschen
Papierkorb
@@ -410,7 +420,7 @@
Sicherheits-Einstellungen
Hauptschlüssel-Einstellungen
Die Datenbank enthält UUID-Duplikate.
- Durch die Validierung dieses Dialogs wird KeePassDX das Problem (durch Erzeugung neuer UUIDs für Duplikate) beheben und weiter ausgeführt.
+ Problem lösen, indem neue UUIDs für Duplikate generiert werden und danach fortfahren\?
Datenbank geöffnet
Eintragsfelder mithilfe der Zwischenablage des Geräts kopieren
Erweitertes Entsperren verwenden, um eine Datenbank einfacher zu öffnen.
@@ -435,13 +445,13 @@
Die Datenbank konnte nicht gespeichert werden.
Datenbank speichern
Papierkorb leeren
- Befehl ausführen …
+ Befehl ausführen…
Sind Sie sicher, dass Sie die ausgewählten Knoten dauerhaft löschen möchten\?
Der Schlüsselspeicher ist nicht richtig initialisiert.
Geben Sie das Passwort ein, bevor Sie auf den Biometrie-Button klicken.
Papierkorb-Gruppe
Datenbank automatisch speichern
- Automatisches Speichern der Datenbank nach einer wichtigen Aktion (nur im Modus \"Bearbeiten\")
+ Automatisches Speichern der Datenbank nach einer wichtigen Aktion (im Modus \"Bearbeiten\")
Anhänge
Historie wiederherstellen
Historie löschen
@@ -449,9 +459,28 @@
Aktion der Go-Taste, die automatisch nach dem Drücken einer Feldtaste ausgeführt wird
%1$s herunterladen
Initialisieren…
- Fortschritt: %1$d%
- Fertigstellung…
+ Fortschritt: %1$d%
+ Fertigstellen…
Vollständig! Tippen Sie, um die Datei zu öffnen.
Abgelaufene Einträge ausblenden
Abgelaufene Einträge werden ausgeblendet
+ App-Design
+ App-Design, das in der App genutzt wird
+
+ - Hell
+ - Dunkel
+ - Schwarz
+ - Klassisch Dunkel
+ - Himmel und Meer
+ - Roter Vulkan
+ - Purple Pro
+
+ Datei Schreibrechte gewähren, um Datenbankänderungen zu speichern
+ Einrichten einer Einmal-Passwortverwaltung (HOTP / TOTP), um ein Token zu generieren, das für die Zwei-Faktor-Authentifizierung (2FA) angefordert wird.
+ Einrichten von OTP
+ Es ist nicht möglich, eine Datenbankdatei zu erstellen.
+ Anhang hinzufügen
+ Verwerfen
+ Änderungen verwerfen\?
+ Validieren
\ No newline at end of file
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 83ec408c0..9dc8cec34 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -113,7 +113,6 @@
Ποτέ
Δεν βρέθηκαν αποτελέσματα αναζήτησης
Εγκαταστήστε ένα πρόγραμμα περιήγησης για να ανοίξετε αυτήν τη διεύθυνση URL.
- Πρόσφατες βάσεις δεδομένων
Να μην γίνει αναζήτηση μέσα από τις καταχωρήσεις αντιγραφών ασφαλείας
Παράληψη ομάδας \"Αντίγραφο Ασφαλείας\" και \"Κάδος Ανακύκλωσης\" από τα αποτελέσματα αναζήτησης
Δημιουργία νέας βάσης δεδομένων…
@@ -136,7 +135,6 @@
Υπογράμμιση
Μη υποστηριζόμενη έκδοση βάσης δεδομένων.
Κεφαλαία
- Μοντάρετε την κάρτα μνήμης για να δημιουργήσετε ή να φορτώσετε μια βάση δεδομένων.
Έκδοση %1$s
Καταχωρίστε τον κωδικό πρόσβασης και /ή το αρχείο-κλειδί για να ξεκλειδώσετε τη βάση δεδομένων σας.
\n
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 1bbe3b3e9..523a8caf1 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -105,7 +105,6 @@
Nunca
Sin resultado de búsqueda
Instale un navegador web para abrir este URL.
- Bases de datos recientes
No buscar en las entradas de respaldo
Omite los grupos «Respaldo» y «Papelera de reciclaje» de los resultados de búsqueda
Creando nueva base de datos…
@@ -125,7 +124,6 @@
Subrayado
No se admite esta versión de la base de datos.
Mayúsculas
- Monte la tarjeta SD para crear o cargar una base de datos.
Versión %1$s
Introduzca una contraseña y/o un archivo de clave para desbloquear su base de datos.
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 096f20150..16634b8b9 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -115,7 +115,6 @@
Inoiz ez
Emaitzarik gabeko bilaketa
URL kudatzeko euskarririk ez.
- Duela gutxiko datubasea ireki :
Ez bilatu segurtasun kopiaren sarreretan
Kendu segurtasun kopien taldea bilaketen emaitzetatik (.kdb fitxategie dagokie bakarrik)
Datubase berria sortzen…
@@ -137,7 +136,6 @@
Azpimarratu
Euskarririk gabeko datubase bertsioa.
Maiuskulak
- Une honetan zure sd txartela ez dago montatua zure dispositiboan. Ezingo duzu zure datubasea kargatu edo sortu.
Bertsioa %1$s
Sartu pasahitz eta / edo gako fitxategi bat zure datubasea desblokeatzeko.
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index ae7125b14..b0a20ce35 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -114,7 +114,6 @@
Ei koskaan
Ei hakutuloksia
Tälle URL:lle ei ole käsittelijää.
- Avaa viimeisin salasanatietokanta :
Älä etsi varmuuskopioista eikä roskakorista
Poista \'Varmuuskopiot\' ja roskakori hakutuloksista
Luodaan uutta tietokantaa…
@@ -136,7 +135,6 @@
Alleviivattu
Ei-tuettu salasanatietokannan versio.
Isot kirjaimet
- SD-korttia ei löydy. Et voi ladata tai tallentaa salasanatietokantaa.
Versio %1$s
Syötä salasana ja/tai avaintiedosto avataksesi tietokantasi.
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 10cdb1588..c44eec20f 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -16,7 +16,8 @@
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see .
--->
+-->
+
Commentaires
Page d’accueil
Implémentation Android du gestionnaire de mots de passe KeePass
@@ -49,7 +50,7 @@
Déchiffrement du contenu de la base de données…
Utiliser comme base de données par défaut
Chiffres
- KeePassDX © %1$d Kunzisoft est <strong>libre</strong> et <strong>sans publicité</strong>. \nIl est fourni tel quel, sous la licence <strong>GPLv3</strong>, sans aucune garantie.
+ Key Derivation Functions
Dernier accès
Annuler
Notes
@@ -123,7 +124,6 @@
Aucun résultat
Installer un navigateur Web pour ouvrir cette URL.
Ouvrir une base de données existante
- Bases de données récentes
Ne pas rechercher dans les entrées sauvegardées
Omet les groupes « Sauvegarde » et « Corbeille » des résultats de recherche
Création d’une nouvelle base de données…
@@ -162,9 +162,8 @@
Majuscules
Alerte
Éviter les caractères en dehors du format de codage de caractères du fichier de base de données (les caractères non reconnus sont convertis en une même lettre).
- Monter la carte mémoire pour créer ou charger une base de données.
- Ne voulez-vous vraiment aucune protection de déverrouillage par mot de passe \?
- Êtes-vous sûr de ne vouloir utiliser aucune clé de chiffrement \?
+ Continuer sans protection de déverrouillage par mot de passe \?
+ Continuer sans clé de chiffrement \?
Version %1$s
La reconnaissance biométrique est prise en charge mais n’est pas configurée.
Ouvrir l’invite biométrique pour déverrouiller la base de données
@@ -198,7 +197,7 @@
Permet de numériser votre empreinte biométrique pour ouvrir la base de données
Supprimer les clés de chiffrement
Supprime toutes les clés de chiffrement liées à la reconnaissance biométrique
- Êtes-vous sûr de vouloir supprimer toutes les clés liées à la reconnaissance biométrique \?
+ Supprimer toutes les clés de chiffrement liées à la reconnaissance biométrique \?
Impossible de démarrer cette fonctionnalité.
Votre version d’Android %1$s est inférieure à la version minimale %2$s requise.
Impossible de trouver le matériel correspondant.
@@ -243,7 +242,7 @@
Associe votre mot de passe à votre empreinte biométrique numérisée pour déverrouiller rapidement votre base de données.
Modifier l’entrée
Modifie votre entrée avec des champs personnalisés. La collection des données peut être référencée entre différents champs de l’entrée.
- Créer un mot de passe fort pour votre entrée.
+ Créer un mot de passe fort
Générez un mot de passe fort à associer avec votre entrée, définissez-le facilement en fonction des critères du formulaire et n’oubliez pas de sécuriser votre mot de passe.
Ajoutez des champs personnalisés
Enregistrez un champ additionnel, ajoutez une valeur et facultativement le protéger.
@@ -416,7 +415,7 @@
Paramètres de sécurité
Paramètres de la clé maîtresse
La base de données contient des doublons d’UUID.
- En validant cette boîte de dialogue, KeePassDX corrigera le problème (en générant de nouveaux UUID pour les doublons) et continuera.
+ Résoudre le problème en générant de nouveaux UUID pour les doublons et continuer \?
Base de données ouverte
Copie les champs d’une entrée à l’aide du presse-papier de votre appareil
Utilise le déverrouillage avancé pour ouvrir plus facilement une base de données
@@ -442,24 +441,24 @@
Enregistrer la base de données
Vider la corbeille
Exécution de la commande…
- Êtes-vous sûr de vouloir supprimer définitivement les nœuds sélectionnés \?
+ Supprimer définitivement les nœuds sélectionnés \?
Le magasin de clés n’est pas correctement initialisé.
Saisissez le mot de passe avant de cliquer sur le bouton biométrique.
Groupe de la corbeille
Enregistrement automatique de la base de données
- Enregistre automatiquement la base de données après une action importante (uniquement en mode « Modifiable »)
+ Enregistre la base de données après chaque action importante (en mode « Modifiable »)
Attachements
Restaurer l\'historique
Effacer l\'historique
Action de touche auto
- Action de la touche Go effectuée automatiquement après avoir appuyé sur une touche de champ
+ Action de la touche « Go » après avoir appuyé sur une touche « Champ »
Téléchargement %1$s
Initialisation…
- En cours : %1$d%
+ En cours : %1$d%
Finalisation…
Terminé ! Appuyer pour ouvrir le fichier.
Masquer les entrées expirées
- Les entrées expirées seront masquées
+ Les entrées expirées sont cachées
Contact
Contribution
Afin de <strong>garder notre liberté</strong>, <strong>corriger les bugs</strong>, <strong>ajouter des fonctionnalités</strong> et <strong>être toujours actif</strong>, nous comptons sur votre <strong>contribution</strong>.
@@ -474,4 +473,11 @@
Masquer les liens rompus de base de données
Masquer les liens rompus dans la liste des bases de données récentes
Accorder un accès en écriture au fichier pour enregistrer les modifications de la base de données
+ Définir le mot de passe à usage unique (temporel ou évènementiel) pour générer un jeton demandé par l’authentification à deux facteurs (A2F).
+ Définir l’OTP
+ Impossible de créer le fichier de base de données.
+ Ajouter une pièce jointe
+ Abandonner
+ Abandonner les modifications \?
+ Valider
\ No newline at end of file
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index 9c04f8c06..c499052c9 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -132,7 +132,6 @@
Instalirajte web preglednik da bi ste otvorili ovaj URL.
Otvori postojeću bazu podataka
Kreiraj novu bazu podataka
- Nedavne baze podataka
Ne pretražuj kopije unosa
Kreiranje nove baze podataka…
Zaštita
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 6506d893c..62cff6555 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -114,7 +114,6 @@
Soha
Nincs találat
Telepítsen egy webböngészőt az URL megnyitásához.
- Korábbi adatbázisok
Ne keressen a biztonsági mentésekben
A „Biztonsági mentés” csoport kihagyása a keresésből (csak a .kdb fájlokra érvényes)
Új adatbázis létrehozása…
@@ -140,7 +139,6 @@
Nagybetűs
Figyelmeztetés
Kerülje a Latin-1 karakterkészlettől eltérő jelszókaraktereket a .kbd fájlokban, mert ugyanarra a betűre lesznek átalakítva.
- Csatolja az SD kártyát, hogy adatbázist hozzon létre vagy töltsön be.
Verzió: %1$s
Az ujjlenyomat-leolvasás támogatott, de nincs beállítva.
Ujjlenyomat-leolvasás
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index ca162efa4..939f0c4d1 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -44,7 +44,7 @@
Decodifica contenuto database…
Usa come database predefinito
Numeri
- KeePassDX © %1$d Kunzisoft è un programma <strong>open source</strong> e <strong>senza pubblicità</strong>.
+ KeePassDX © %1$d Kunzisoft è un programma <strong>libero</strong> e <strong>senza pubblicità</strong>.
\nViene distribuito sotto le condizioni della licenza <strong>GPL versione 3</strong> o successiva, senza alcuna garanzia.
Note
Apri un database esistente
@@ -78,13 +78,13 @@
File non trovato. Prova a riaprirlo dal tuo gestore di file.
Gestore file
Genera password
- conferma password
- password generata
+ Conferma password
+ Password generata
Nome gruppo
File chiave
- lunghezza
+ Lunghezza
Password
- password
+ Password
Installa dal Play Store
Installa dal F-Droid
Non è possibile leggere le credenziali. Se questo dovesse riaccadere, il file del databese potrebbe essere corrotto.
@@ -115,7 +115,6 @@
Mai
Nessun risultato di ricerca
Installa un browser web per aprire questo URL.
- Database recenti
Non cercare nelle voci di backup
Ometti i gruppi \"Backup\" e \"Cestino\" dai risultati di ricerca
Creazione nuovo database…
@@ -139,12 +138,11 @@
Maiuscole
Attenzione
Evita password con caratteri al di fuori del formato di codifica del testo nel file di database (i caratteri non riconosciuti vengono convertiti nella stessa lettera).
- Monta la scheda di memoria per poter creare o caricare un database.
Versione %1$s
La scansione di impronte è supportata ma non impostata.
Scansione impronte
Password criptata salvata
- Lettura dell\'impronta fallita. Ripristina la tua password.
+ Impossibile leggere la chiave biometrica. Eliminala e ripeti la procedura di riconoscimento.
Problema impronta: %1$s
Usa l\'impronta per salvare questa password
Questo database non ha ancora alcuna password.
@@ -200,8 +198,8 @@
Creazione
Modifica
Accesso
- Vuoi veramente che non ci sia una password di sblocco\?
- Sei sicuro di non volere usare una chiave di cifratura?
+ Continuare senza aver impostato una password di sblocco \?
+ Continuare senza una chiave di cifratura\?
Impronta non riconosciuta
Cronologia
Aspetto
@@ -223,10 +221,10 @@
Blocca il database quando lo schermo è spento
Impronta digitale
Scansione di impronte
- Consente la scansione di impronte per aprire il database
+ Consente la scansione biometrica per aprire il database
Elimina chiavi di cifratura
Elimina tutte le chiavi di cifratura relative al riconoscimento dell\'impronta
- Sei sicuro di volere eliminare tutte le chiavi relative alle impronte?
+ Eliminare tutte le chiavi di cifrature associate al riconoscimento biometrico \?
Impossibile avviare questa funzione.
La tua versione di Android %1$s non è la minima %2$s richiesta.
L\'hardware relativo non è stato trovato.
@@ -236,7 +234,7 @@
Crea un nuovo database
Percorso file
Visualizza il percorso file completo
- Usa il cestino
+ Uso del Cestino
Sposta i gruppi e le voci nel gruppo \"Cestino\" prima di eliminarlo
Carattere campi
Cambia il carattere usato nei campi per una migliore visibilità
@@ -405,6 +403,51 @@
Salva il database
Svuota il cestino
Esecuzione del comando…
- Sei sicuro di voler eliminare definitivamente i nodi selezionati\?
+ Vuoi eliminare definitivamente i nodi selezionati\?
Allegati
+ Richiedi una ricerca quando un database viene aperto
+ Ricerca rapida
+ Cancella cronologia
+ Ripristina cronologia
+ Per poter <strong>mantenere la nostra libertà</strong>, <strong>risolvere bug</strong>, <strong>aggiungere funzionalità</strong> ed <strong>essere sempre attivi</strong>, facciamo affidamento sul tuo <strong>contributo</strong>.
+ Contatto
+ Apri il database con il riconoscimento biometrico
+ Salva il riconoscimento biometrico
+ Il keystore non è inizializzato correttamente.
+ Impostazioni della chiave principale
+ Chiave principale
+ Contribuisci
+ Attenzione: Devi comunque ricordarti la password principale anche se usi il riconoscimento biometrico.
+ Garantisci il permesso di scrittura per salvare i cambiamenti del database
+ Nascondi link corrotti nella lista dei database recenti
+ Nascondi i link di database corrotti
+ Mostra le posizioni dei database recenti
+ Mostra file recenti
+ Salva la posizione dei keyfile
+ Ricorda la posizione dei database
+ Salva posizione dei database
+ Per continuare, risolvi il problema generando nuovi UUIDs per i duplicati \?
+ Impossibile creare il file del database.
+ Aggiungi allegato
+ Scarta
+ Scartare i cambiamenti\?
+ Convalida
+ Dimensione massima
+ Numero massimo
+ Apri automaticamente prompt biometrico
+ Limita la dimensione (in byte) della cronologia per voce
+ Limita il numero di elementi della cronologia per voce
+ Gruppo cestino
+ La compressione dei dati riduce le dimensioni del database.
+ Compressione dati
+ Apri automaticamente il prompt biometrico quando viene definita una chiave biometrica per un database
+ Utilizza lo sblocco avanzato per aprire il database più facilmente
+ Copia i campi di immissione utilizzando gli appunti del tuo dispositivo
+ Database aperto
+ Biometrico
+ Digitare la password prima di fare clic sul pulsante biometrico.
+ Estrai le credenziali del database con dati biometrici
+ Forza rinnovo
+ Consigliato cambiare la chiave principale (giorni)
+ Rinnovo raccomandato
\ No newline at end of file
diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml
index 9b39fdc71..fdeff0b92 100644
--- a/app/src/main/res/values-iw/strings.xml
+++ b/app/src/main/res/values-iw/strings.xml
@@ -111,7 +111,6 @@
אף פעם
אין תוצאות חיפוש
אין מטפל לכתובת url זו.
- פתח מסד נתונים אחרון :
אל תחפש ערכי גיבוי
הורד את קבוצת \"גיבוי\" מתוצאות חיפוש (תואם רק לקבצי kdb)
צור מסד נתונים חדש…
@@ -130,7 +129,6 @@
קו תחתון
גרסת מסד נתונים לא נתמכת.
רישית
- כרטיס ה-SD במצב לקריאה בלבד. אתה לא תוכל לשמור או ליצור במסד הנתונים.
גרסה %1$s
הזן סיסמה ו/או קובץ מפתח כדי לפתוח את מסד הנתונים.
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 2e038403c..7e0b057ac 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -103,7 +103,6 @@
期限なし
検索結果に該当するものはありません。
このURLを処理できません。
- 以前使用したデータベースを開く:
検索対象から除外
\"バックアップ\"と\"ごみ箱\"を検索対象から除外します
データベースファイルを作成中…
@@ -123,7 +122,6 @@
アンダーライン (_)
このバージョンのデータベースはサポートされていません。
英数大文字
- SDカードがマウントされていません。データベースの読込や作成ができません。
バージョン %1$s
データベースに設定したパスワードを入力するかキーファイルを選択してください。
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 13e7c2b78..f58fa9da4 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -137,7 +137,6 @@
이 URL을 열기 위해 웹 브라우저를 설치하십시오.
가지고 있는 데이터베이스 열기
새 데이터베이스 생성
- 최근 데이터베이스
백업 항목 검색하지 않기
새 데이터베이스 생성 중…
작업 중…
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index f444b4fc4..f7ef3c293 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -86,7 +86,6 @@
Mažosios raidės
Minusas
Pabraukimas
- Atidaryti naujausią duomenų bazę
Naudoti šią duomenų bazę kaip numatytąją
Slėpti slaptažodžius pagal nutylėjimą
Neteisingas algoritmas.
diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml
index c20b85eb8..73297ba36 100644
--- a/app/src/main/res/values-lv/strings.xml
+++ b/app/src/main/res/values-lv/strings.xml
@@ -94,7 +94,6 @@
Nekad
Nav meklēšanas rezultātu
Neizdevās atvērt saiti.
- Atvērt pēdējo datu bāzi :
Nemeklēt kopijās un atkritnē
Izlaist kopijas un atkritni no meklēšanas rezultātiem
Izveido jaunu datu bāzi…
@@ -116,7 +115,6 @@
Pasvītrojums
Neatbalstīta datu bāzes versija.
Lielie burti
- Nav SD kartes. Darbības ar datu bāzi nav iespējamas.
Versija %1$s
Ievadiet paroli/atslēgas failu, lai atbloķētu savu datu bāzi.
diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml
index c32746f85..f85f092a0 100644
--- a/app/src/main/res/values-nb/strings.xml
+++ b/app/src/main/res/values-nb/strings.xml
@@ -16,7 +16,8 @@
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see .
--->
+-->
+
Tilbakemelding
Hjemmeside
Android-implementasjon av KeePass-passordsbehandleren
@@ -48,7 +49,8 @@
Dekrypterer databaseinnhold…
Bruk dette som forvalgt database
Siffer
- KeePassDX © %1$d Kunzisoft kommer uten noen form for garanti. Dette er fri programvare, og du er velkommen til å redistribuere det i henhold til vilkårene i GPL versjon 3 eller senere.
+ KeePassDX © %1$d Kunzisoft er <strong>fri programvare</strong>, og <strong>reklamefritt</strong>.
+\nDet tilbys som det er, i hendhold til <strong>GPL versjon 3 eller senere</strong>, uten noen garantier.
Brukt
Avbryt
Kommentarer
@@ -135,7 +137,6 @@
Ingen søkeresultater
Kan ikke håndtere denne nettadressen.
Velg en eksisterende database
- Nylige databaser
Ikke søk gjennom sikkerhetskopioppføringer
Utelat \"Sikkerhetskopi\"-gruppen fra søkeresultater (har kunn innvirkning på .kdb-filer)
Oppretter ny database…
@@ -174,7 +175,6 @@
Store bokstaver
Advarsel
Unngå passordtegn utenfor tekstkodingsformat i databasefil (ukjente tegn blir konvertert til samme bokstav).
- SD-kortet ditt er ikke montert på enheten din. Du vil ikke kunne laste inne eller opprette din database.
Ønsker du virkelig å bruke en tom streng som ditt passord?
Er du sikker på at du ønsker å bruke en krypteringsnøkkel?
Versjon %1$s
@@ -382,8 +382,8 @@
Minst én identitetsdetalj må angis.
Du kan ikke kopiere en gruppe hit.
Hemmelig nøkkel må være i Base32-format.
- "Symbolet må inneholde %1$d til %2$d siffer."
- %1$d med samme UUID %2$s finnes allerede.
+ Symbolet må inneholde %1$d til %2$d siffer.
+ %1$s med samme UUID %2$s finnes allerede.
Oppretter database…
Sikkerhetsinnstillinger
Hovednøkkelinnstillinger
@@ -408,4 +408,8 @@
Fullfører…
Fullført. Trykk for å åpne filen.
Skjul utløpte oppføringer
+ Hurtigsøk
+ Legg til vedlegg
+ Bidrag
+ Kontakt
\ No newline at end of file
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index ebac28b63..a9c528b6a 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -105,7 +105,6 @@
Nooit
Geen zoekresultaten
Installeer een webbrowser om deze URL te openen.
- Recente databanken
Back-upitems niet doorzoeken
Hiermee worden groepen \"Back-up\" en \"Prullenbak\" uit de zoekresultaten weggelaten
Bezig met creëren van nieuwe databank…
@@ -125,7 +124,6 @@
Onderstrepen
Niet-ondersteunde databankversie.
Hoofdletters
- Koppel de SD-kaart aan om een databank te creëren of laden.
Versie %1$s
Geef het wachtwoord en/of sleutelbestand op om je databank te ontgrendelen.
\n
@@ -278,7 +276,7 @@
Voeg items toe om je digitale identiteiten te beheren.
\n
\nVoeg groepen toe (groepen zijn gelijk aan mappen) om items in je databank te organiseren.
- "Doorzoek al je items"
+ Doorzoek al je items
Doorzoek items op titel, gebruikersnaam of andere velden om wachtwoorden te vinden.
Ontgrendel de databank met je vingerafdruk
Koppel je wachtwoord en vingerafdruk om de databank snel te ontgrendelen.
diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml
index 5159725ee..6fc7ee191 100644
--- a/app/src/main/res/values-nn/strings.xml
+++ b/app/src/main/res/values-nn/strings.xml
@@ -104,7 +104,6 @@
Aldri
Ingen søkjeresultat
Ingen behandlar for denne adressa.
- Opna nyleg brukt database :
Søk ikkje i kopipostane eller søppelbøtta
Søkjeresultatet inneheld ikkje oppføringar frå \'Backup\' eller søppelbøtta
Lager ny database …
@@ -124,7 +123,6 @@
Understreking
Kan ikkje bruka databaseutgåva.
Store bokstavar
- SD-kortet er ikkje montert i eininga di. Du kan verken henta eller laga databasen din.
Utgåve %1$s
Skriv inn passordet og/eller nøkkelfil for å låsa opp databasen.
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index f416fdd2f..89308c663 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -102,7 +102,6 @@
Nigdy
Brak wyników wyszukiwania
Zainstaluj przeglądarkę internetową, aby otworzyć ten adres URL.
- Ostatnio używana baza danych
Nie wyszukuj wpisów kopii zapasowej
Pomija grupy \"Kopia zapasowa\" i \"Kosz\" z wyników wyszukiwania
Tworzenie nowej bazy danych…
@@ -122,7 +121,6 @@
Podkreślenie
Nieobsługiwana wersja bazy danych.
Wielkie litery
- Zainstaluj kartę pamięci, aby utworzyć lub załadować bazę danych.
prowadź hasło i/lub plik klucza, aby odblokować bazę danych.
\n
\nUtwórz kopię zapasową pliku bazy danych w bezpiecznym miejscu po każdej zmianie.
@@ -152,8 +150,9 @@
Niektóre urządzenia nie pozwalają aplikacjom korzystać ze schowka.
Nie można wyczyścić schowka
Przesuń, by wyczyścić schowek
- KeePassDX © %1 $d Kunzisoft jest <strong>open source</strong> i <strong>bez reklam</strong>.
+ KeePassDX © %1 $d Kunzisoft jest <strong>wolnym programem</strong> i <strong>bez reklam</strong>.
\nJest on dostarczany w stanie, zgodnie z licencją <strong>GPLv3</strong> bez żadnych gwarancji.
+>>>>>>> translations
Nie znaleziono danych wejściowych.
Nie można załadować bazy danych.
Nie można załadować klucza. Spróbuj zmniejszyć użycie pamięć KDF.
@@ -196,8 +195,8 @@
Unikaj znaków hasła spoza formatu kodowania tekstu w pliku bazy danych (nierozpoznane znaki są konwertowane na tę samą literę).
Kosz na dole
Tytuł
- Czy naprawdę nie chcesz ochrony przed odblokowaniem hasła\?
- Czy na pewno nie chcesz używać żadnego klucza szyfrowania?
+ Kontynuować bez ochrony odblokowującej hasło\?
+ Kontynuować bez klucza szyfrowania\?
Wersja %1$s
Skanowanie odcisków palców jest obsługiwane, ale nie skonfigurowane.
Zapisano zaszyfrowane hasło
@@ -232,7 +231,7 @@
Umożliwia zeskanowanie danych biometrycznych w celu otwarcia bazy danych
Usuń klucze szyfrowania
Usuń wszystkie klucze szyfrowania związane z rozpoznawaniem linii papilarnych
- Czy na pewno chcesz usunąć wszystkie klucze związane z rozpoznawaniem linii papilarnych\?
+ Czy usunąć wszystkie klucze szyfrowania związane z rozpoznawaniem biometrycznym\?
Nie można uruchomić tej funkcji.
Twoja wersja Androida %1$s nie spełnia wymaganej minimalnej wersji %2$s.
Nie można znaleźć odpowiedniego sprzętu.
@@ -281,7 +280,7 @@
Połącz swoje hasło z zeskanowanym odciskiem palca, aby szybko odblokować bazę danych.
Edytuj wpis
Edytuj swój wpis za pomocą pól niestandardowych. Dane puli mogą być przywoływane między różnymi polami wprowadzania.
- Utwórz silne hasło do swojego wpisu.
+ Utwórz silne hasło
Wygeneruj silne hasło, które będzie kojarzyć się z Twoim wpisem, łatwo zdefiniuj je zgodnie z kryteriami formularza i nie zapomnij o bezpiecznym haśle.
Dodaj niestandardowe pola
Zarejestruj dodatkowe pole, dodaj wartość i opcjonalnie chroń je.
@@ -420,7 +419,7 @@
Okres musi wynosić od %1$d do %2$d sekund.
Token musi zawierać cyfry od %1$d do %2$d.
%1$s o tym samym identyfikatorze UUID %2$s już istnieje.
- Weryfikując to okno dialogowe, KeePassDX rozwiąże problem (poprzez wygenerowanie nowych UUID dla duplikatów) i będzie kontynuował.
+ Rozwiązać problem poprzez stworzenie nowych identyfikatory UUID duplikatów, aby kontynuować\?
Skopiuj pola wprowadzania danych za pomocą schowka urządzenia
Użyj zaawansowanego odblokowywania w celu łatwiejszego otwierania bazy danych
Kompresja danych zmniejsza rozmiar bazy danych.
@@ -433,24 +432,24 @@
Zapisz bazę danych
Opróżnij kosz
Wykonywanie polecenia…
- Czy na pewno chcesz trwale usunąć wybrane węzły\?
+ Czy trwale usunąć wybrane węzły\?
Magazyn kluczy nie został poprawnie zainicjowany.
Wpisz hasło przed kliknięciem przycisku biometrycznego.
Kosz grupy
Automatycznie zapisuj bazę danych
- Automatycznie zapisz bazę danych po ważnym działaniu (tylko w trybie „Modyfikowalnym”)
+ Zapisz bazę danych po każdym ważnym działaniu (w trybie „Modyfikowalnym”)
Załączniki
Przywróć historię
Usuń historię
Automatyczne działanie klucza
- Działanie klawisza Go wykonywane jest automatycznie po naciśnięciu klawisza Field
+ Akcja klawisza „Idź” po naciśnięciu klawisza „Pole”
Pobierz %1$s
Inicjowanie…
- W trakcie realizacji: %1$d%
+ W trakcie realizacji: %1$d%
Kończę…
Kompletny! Stuknij, aby otworzyć plik.
Ukryj wygasłe wpisy
- Wygasłe wpisy zostaną ukryte
+ Wygasłe wpisy są ukryte
Kontakt
Aby <strong>zachować naszą wolność</strong>, <strong>sprawdzać błędy</strong>, <strong>dodać funkcje</strong> i <strong>by być zawsze aktywnym</strong>, liczymy na twój <strong>wkład</strong>.
Szybkie wyszukiwanie
@@ -465,4 +464,11 @@
Ukryj uszkodzone łącza na liście najnowszych baz danych
Przyznaj dostęp do zapisu pliku, aby zapisać zmiany w bazie danych
Wkład
+ Skonfiguruj zarządzanie hasłem jednorazowym (HOTP / TOTP), aby wygenerować token wymagany do uwierzytelniania dwuskładnikowego (2FA).
+ Konfiguracja OTP
+ Nie można utworzyć pliku bazy danych.
+ Dodaj załącznik
+ Odrzuć
+ Odrzucić zmiany\?
+ Walidacja
\ No newline at end of file
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index cd8717d45..138e29446 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -103,7 +103,6 @@
Nunca
Sem resultados na busca
Instale um navegador para abrir esta URL.
- Bancos de dados recentes
Não procurar por entradas no backup ou na lixeira
Omite os grupos \"Backup\" e \"Lixeira\" dos resultados da busca
Criando novo banco de dados…
@@ -123,7 +122,6 @@
Sublinhado
Versão de banco de dados não suportada.
Letras maiúsculas
- Monte o cartão SD para criar ou abrir um banco de dados.
Versão %1$s
Entre com a senha e/ou com o caminho para o arquivo-chave do banco de dados.
\n
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index 70d18d0b1..34711588d 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -115,7 +115,6 @@
Nunca
A pesquisa não obteve resultados
Instale um navegador para abrir esta URL.
- Bancos de dados recentes
Não procurar por entradas no backup ou na lixeira
Omite os grupos \"Backup\" e \"Lixeira\" dos resultados da busca
A criar nova base de dados…
@@ -141,7 +140,6 @@
Maiúsculas
Aviso
Evite caracteres fora do formato de codificação do ficheiro do banco (todos os caracteres não reconhecidos são convertidos para a mesma letra).
- Monte o cartão SD para criar ou abrir um banco de dados.
Versão %1$s
Entre com a palavra-passe e/ou com o caminho para o ficheiro-chave do banco de dados.
\n
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index a29062d8e..55fac8a63 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -43,7 +43,7 @@
Actualizați
Elimina
Câmpuri închise
- %1$s is either \\\"Nume\\\" si \\\"Parola\\\".
+ Selectați pentru a copia %1$s în clipboard
Obtinerea cheii bazei de date…
Baza de date
Decriptarea continutului bazei de date.…
@@ -167,16 +167,15 @@
Minus
Niciodata
Nu există Rezultate
- KeePassDX © %1$d Kunzisoft is <strong>sursa deschisa<strong> and <strong>fara publicitate<strong>.
-\nEste prevăzut așa cum este, sub <strong>GPLv3<strong> licenta,fara nici un fel de garantie.
- In oridine sa <strong>pastram libertatea noastra <strong>, <strong>fix bugs<strong>, <strong>adăugați funcții<strong> si<strong>sa fie intotdeauna activ<strong>", ne bazam pe "<strong>contributie.<strong>
+ KeePassDX © %1$d Kunzisoft is <strong>sursa deschisa<strong> and <strong>fara publicitate</strong>.
+\nEste prevăzut așa cum este, sub <strong>GPLv3</strong> licenta, fara nici un fel de garantie.
+ In oridine sa <strong>pastram libertatea noastra</strong>, <strong>fix bugs</strong>, <strong>adăugați funcții</strong> si<strong>sa fie intotdeauna activ<strong>, ne bazam pe <strong>contributie</strong>.
Ascundeți parolele
Mascați parolele (***) în mod implicit
Despre
Instalați un browser web pentru a deschide această adresă URL.
Deschide baza de date existentă
Creați o bază de date nouă
- Baze de date recente
Crearea noii baze de date …
Lucrând …
Protecție
@@ -217,7 +216,6 @@
Cu majuscule
Avertizare
Evitați caracterele parole în afara formatului de codare a textului în fișierul bazei de date (caracterele nerecunoscute sunt convertite în aceeași literă).
- Montați cardul de memorie pentru a crea sau încărca o bază de date.
Chiar nu doriți nicio protecție de deblocare a parolei\?
Ești sigur că nu vrei să folosești nicio cheie de criptare\?
Sigur doriți să ștergeți definitiv nodurile selectate\?
@@ -394,7 +392,7 @@
Cumpărând versiunea pro, veți avea acces la acest <strong> stil vizual </strong> și vă va ajuta în special <strong> implementarea proiectelor comunitare. </strong>
Acest <strong> stil vizual </strong> este disponibil datorită generozității tale.
Pentru a ne păstra libertatea și pentru a fi mereu activi, ne bazăm pe contribuția dvs. <strong>. </strong>
- Această caracteristică este <strong> în curs de dezvoltare </strong> și necesită ca contribuția dvs <strong> să fie disponibilă în curând.
+ Această caracteristică este <strong> în curs de dezvoltare</strong> și necesită ca <strong>contribuția</strong> dvs să fie disponibilă în curând.
Cumpărând versiunea <strong> pro </strong>,
Prin <strong> contribuție </strong>,
încurajezi dezvoltatorii să creeze <strong> funcții noi </strong> și să <strong> remedieze erori </strong> în conformitate cu observațiile tale.
@@ -405,7 +403,7 @@
Contribuie
Descărcați %1$s
Inițializare …
- In progress: %1$d%
+ In progress: %1$d%
Finalizare …
Complet! Atingeți pentru a deschide fișierul.
Rijndael (AES)
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 41870ed89..d1fec7600 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -43,7 +43,7 @@
Расшифровка базы…
База по умолчанию
Цифры
- KeePassDX © %1$d Kunzisoft с <strong>открытым исходным кодом</strong> и <strong>без рекламы</strong>.
+ KeePassDX © %1$d Kunzisoft — это <strong>свободное программное обеспечение</strong> и <strong>без рекламы</strong>.
\nРаспространяется под лицензией <strong>GPLv3</strong> без каких-либо гарантий.
Открыть существующую базу
Доступ
@@ -115,7 +115,6 @@
Никогда
Совпадения не найдены
Установите браузер, чтобы открыть этот URL.
- Недавно открытые базы
Не искать в резервных копиях
Не искать в группах \"Резервирование\" и \"Корзина\"
Создание новой базы…
@@ -141,7 +140,6 @@
ЗАГЛАВНЫЕ
Внимание
Избегайте использования в пароле символов вне кодировки текста в файле базы, так как эти символы будут преобразованы в одинаковый символ.
- Подключите хранилище для создания или загрузки базы.
Версия %1$s
Биометрия поддерживается, но не настроена.
Ожидание биометрического ключа для разблокировки базы
@@ -205,8 +203,8 @@
Сначала группы
\"Корзина\" внизу
Название записи
- Вы действительно не хотите использовать пароль для защиты базы\?
- Вы действительно не хотите использовать ключ шифрования?
+ Продолжить без пароля для защиты базы\?
+ Продолжить без ключа шифрования\?
Биометрический ключ не распознан
История
Внешний вид
@@ -232,7 +230,7 @@
Включить разблокировку базы при помощи биометрического ключа
Удалить ключи шифрования
Удалить все ключи шифрования, связанные с распознаванием биометрического ключа
- Вы уверены, что хотите удалить все ключи, связанные с биометрическим ключом\?
+ Удалить все ключи шифрования, связанные с биометрическим распознаванием\?
Невозможно запустить эту функцию.
Ваша версия Android %1$s ниже минимально необходимой %2$s.
Соответствующее оборудование не найдено.
@@ -281,7 +279,7 @@
Ищите записи по названию, имени или другим полям для быстрого доступа к своим паролям.
Редактируйте записи
Редактируйте записи с настраиваемыми полями. Возможны перекрёстные ссылки между полями разных записей.
- Создайте надёжный пароль для записи.
+ Создайте надёжный пароль
Создайте надёжный пароль, связанный с записью, легко настраиваемый под критерии формы. И не забудьте главный пароль от базы.
Добавляйте настраиваемые поля
Зарегистрируйте дополнительное поле, добавьте значение и при необходимости защитите его.
@@ -388,14 +386,14 @@
Безопасность
История
Настройка одноразового пароля
- Тип одноразового пароля
+ Тип OTP
Секретный ключ
Время (в секундах)
Счётчик
Цифры
Алгоритм
- Одноразовый пароль
- Недействительный секретный ключ одноразового пароля.
+ OTP
+ Некорректный OTP.
Должен быть установлен, по крайней мере, один пароль.
Вы не можете копировать группу сюда.
Секретный ключ должен быть в формате BASE32.
@@ -407,7 +405,7 @@
Настройки безопасности
Настройки главного пароля
База содержит повторяющиеся UUID.
- Если вы разрешите, KeePassDX исправит проблему (путём создания новых UUID для дубликатов) и продолжит работу.
+ Исправить проблему путём создания новых UUID для дубликатов и продолжить работу\?
База открыта
Копирование полей ввода с помощью буфера обмена устройства
Использовать дополнительную разблокировку для более лёгкого открытия базы данных
@@ -433,20 +431,20 @@
Сохранить базу
Очистить \"корзину\"
Выполнение команды…
- Вы уверены, что хотите навсегда удалить выбранные узлы\?
+ Безвозвратно удалить выбранные узлы\?
Хранилище ключей не инициализировано должным образом.
Введите пароль перед нажатием кнопки биометрии.
Группа \"корзины\"
Автосохранение базы
- Автоматическое сохранение базы после каждого важного действия (только в \"режиме записи\")
+ Сохранять базу после каждого важного действия (в \"режиме записи\")
Вложения
Восстановить историю
Удалить историю
Автоматическое действие кнопки
- Выполнять команду \"Ввод\" автоматически после нажатия кнопки заполнения поля
+ Выполнять команду \"Ввод\" после нажатия кнопки заполнения поля
Скачать %1$s
Инициализация…
- Выполнение: %1$d%
+ Выполнение: %1$d%
Завершение…
Готово! Нажмите, чтобы открыть файл.
Скрывать устаревшие записи
@@ -465,4 +463,11 @@
Скрывать отсутствующие
Не показывать неработающие ссылки в списке последних открытых баз
Необходимо разрешение на запись в файл для сохранения изменений базы
+ Проверить
+ Отменить изменения\?
+ Отменить
+ Добавить вложение
+ Невозможно создать файл базы.
+ Настройте OTP
+ Настройте управление одноразовыми паролями (HOTP / TOTP) для создания токена, запрашиваемого при двухфакторной аутентификации (2FA).
\ No newline at end of file
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index e4e1eeaff..c97bb5836 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -103,7 +103,6 @@
Nikdy
Žiadne výsledky hľadania
Žiaden manažér pre url.
- Otvoriť poslednú databázu :
Neprehľadávať položky
Vynechať skupinu \'Backup\' a Recycle Bin z výsledkov hľadania
Vytváram novú databázu…
@@ -123,7 +122,6 @@
Podčiarknuté
Nepodporovaná verzia databázy.
Veľké písmená
- Vaša SD karta nie je momentálne pripojená k zariadeniu. Nemôžete načítať, alebo vytvoriť databázu.
Version %1$s
Vložte heslo a / alebo keyfile pre odomknutie databázy.
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 7c1866ac7..cc17ce5c5 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -114,7 +114,6 @@
Aldrig
Inget sökresultat
Installera en webbläsare för att öppna denna URL.
- Senast öppnade databaser
Sök inte efter backup-poster
Utelämnar poster i grupperna \"Backup\" och \"Papperskorg\"
Skapar ny databas…
@@ -136,7 +135,6 @@
Understreck
Databasversionen stöds ej.
Versaler
- Montera SD-kortet för att skapa eller ladda in en databas.
Version %1$s
Ange lösenord och/eller nyckelfil för att öppna databasen.
\n
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 1da29f955..93fbfd0d6 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -16,7 +16,8 @@
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see .
--->
+-->
+
Geri Bildirim
Ana sayfa
KeePass parola yöneticisinin Android uygulaması
@@ -64,7 +65,8 @@
Veritabanı içeriği deşifre ediliyor…
Varsayılan veritabanı olarak kullan
Rakamlar
- KeePassDX © %1$d Kunzisoft kesinlikle bir garanti vermez. Bu, libre yazılımıdır ve GPL sürüm 3 veya üzeri şartlar altında yeniden dağıtmanız mümkündür.
+ KeePassDX © %1$d Kunzisoft <strong>özgür yazılımdır</strong> ve <strong>reklam içermez</strong>.
+\n<strong>GPLv3</strong> lisansı altında sağlanmaktadır, herhangi bir garanti vermez.
Süre sonu
Anahtar dosya
Arcfour akış şifresi desteklenmiyor.
@@ -76,7 +78,7 @@
En az bir parola oluşturma türü seçilmelidir.
Parolalar uyuşmuyor.
\"Dönüşüm turları\" çok yüksek. 2147483648\'e ayarlayın.
- Her dizenin bir alan adı olmalıdır.
+ Her dizginin bir alan adı olmalıdır.
\"Uzunluk\" alanına pozitif bir tam sayı girin.
Otomatik doldurma hizmeti etkinleştirilemedi.
Bir grubu kendine taşıyamazsın.
@@ -135,7 +137,6 @@
Bu URL\'u açmak için bir web tarayıcısı yükleyin.
Mevcut veritabanını aç
Yeni veritabanı oluştur
- Son veritabanları
Yedek girişleri arama
Arama sonuçlarından \"Yedekleme\" ve \"Geri dönüşüm kutusu\" gruplarını atlar
Yeni veritabanı oluştur…
@@ -175,9 +176,8 @@
Büyük harf
Uyarı
Veritabanı dosyasındaki metin kodlama formatının dışındaki parola karakterlerinden kaçının (tanınmayan karakterler benzer harfe dönüştürülür).
- Bir veritabanı oluşturmak veya yüklemek için hafıza kartını takın.
- Gerçekten parolasız açma koruması mı istiyorsunuz\?
- Herhangi bir şifreleme anahtarı kullanmak istemediğinize emin misiniz\?
+ Parola kilidi koruması olmadan devam edilsin mi\?
+ Şifreleme anahtarı olmadan devam edilsin mi\?
Sürüm %1$s
Yapı %1$s
Parmak izi taraması desteklenir, ancak kurulmaz.
@@ -212,7 +212,7 @@
Veritabanını açmak için biyometriklerinizi taramanızı sağlar
Şifreleme anahtarlarını silin
Parmak izi tanıma ile ilgili tüm şifreleme anahtarlarını silin
- Parmak izi tanıma ile ilgili tüm tuşları silmek istediğinizden emin misiniz\?
+ Biyometrik tanıma ile ilgili tüm şifreleme anahtarları silinsin mi\?
Bu özellik başlatılamadı.
Android sürümünüz %1$s, gerekli minimum %2$s sürümünü karşılamıyor.
İlgili donanım bulunamadı.
@@ -278,10 +278,10 @@
Veritabanınızı hızlıca açmak için parolanızı taranan parmak izinize bağlayın.
Girdiyi düzenle
Girdinizi özel alanlarla düzenleyin. Havuz verileri farklı giriş alanları arasında referans alınabilir.
- Girdiniz için güçlü bir parola oluşturun.
+ Güçlü bir parola oluşturun
Girişinizle ilişkilendirmek için güçlü bir şifre oluşturun, formun kriterlerine göre kolayca tanımlayın ve güvenli şifreyi unutmayın.
Özel alanlar ekle
- Ayrıca koruyabileceğiniz yeni bir formu doldurarak temel bir tedarik edilmemiş alanı kaydedin.
+ Ek bir alan kaydedin, bir değer ekleyin ve isteğe bağlı olarak koruyun.
Veritabanınızın kilidini açın
Veritabanınızın kilidini açmak için parola ve/veya anahtar dosya girin.
\n
@@ -301,7 +301,7 @@
Girdilerin ve grupların nasıl sıralandığını seçin.
Katıl
Daha fazla özellik ekleyerek istikrarı, güvenliği artırmaya yardımcı olun.
- Birçok parola yönetimi uygulamasının aksine, bu uygulama <strong>reklam içermez</strong>, <strong>açık kaynaklı</strong> ve <strong>copyleft lisanslıdır</strong>. Hangi sürümü (ücretsiz veya profesyonel) kullanırsanız kullanın, herhangi bir biçimde <strong>kişisel veri toplanmamaktadır</strong>.
+ Birçok parola yönetimi uygulamasının aksine, bu uygulama <strong>reklam içermez</strong>, <strong> copyleft lisanslı özgür yazılımdır</strong> ve hangi sürümü kullanırsanız kullanın, sunucularında kişisel veri toplamaz.
Profesyonel sürümü satın alarak, bu <strong>görsel stile</strong> erişebilecek ve özellikle <strong>topluluk projelerinin gerçekleştirilmesine</strong> yardımcı olacaksınız.
Bu <strong>görsel stil</strong>, cömertliğiniz sayesinde kullanılabilir.
Özgürlüğümüzü korumak ve daima aktif olmak için <strong>katkılarınıza</strong> güveniyoruz
@@ -390,7 +390,7 @@
Güvenlik ayarları
Ana anahtar ayarları
Veritabanı tekrarlanan UUID\'ler içermektedir.
- Bu iletişim kutusunu doğrulayarak, KeePassDX sorunu çözecek (tekrarlananlar için yeni UUID\'ler oluşturarak) ve devam edecektir.
+ Tekrarlananlar için yeni UUID\'ler oluşturarak sorunu çöz ve devam et\?
Veritabanı açıldı
Cihazınızın panosunu kullanarak giriş alanlarını kopyala
Veritabanını daha kolay açmak için gelişmiş kilit açma özelliğini kullan
@@ -404,29 +404,29 @@
Ana anahtarın değiştirilmesini öner (gün)
Yenilemeyi zorla
Ana anahtarın değiştirilmesini gerektir (gün)
- Bir dahaki sefere yenilemeyi zorla
+ Bir dahaki sefere yenilemeye zorla
Bir dahaki sefere ana anahtarı değiştirmeyi gerektirir (bir kez)
Varsayılan kullanıcı adı
Özel veritabanı rengi
Sıkıştırma
Yok
gzip
- Cihaz klavye Ayarları
+ Cihaz klavye ayarları
Veritabanı kaydedilemedi.
Veritabanını kaydet
Geri dönüşüm kutusunu boşalt
Komut çalıştırılıyor…
- Seçili düğümleri kalıcı olarak silmek istediğinizden emin misiniz\?
+ Seçilen düğümler kalıcı olarak silinsin mi\?
Anahtar deposu düzgün bir şekilde başlatılmadı.
Biyometrik butona tıklamadan önce şifreyi yazın.
Geri dönüşüm kutusu grubu
Veritabanını otomatik kaydet
- Önemli bir işlemden sonra veritabanını otomatik olarak kaydet (yalnızca \"Değiştirilebilir\" modunda)
+ Her önemli işlemden sonra veri tabanını kaydet (\"Değiştirilebilir\" modda)
Ekler
Geçmişi geri yükle
Geçmişi sil
Otomatik tuş eylemi
- Alan tuşuna bastıktan sonra otomatik olarak gerçekleştirilen Git tuşunun eylemi
+ \"Alan\" tuşuna bastıktan sonra \"Git\" tuşu eylemi
İndir %1$s
Başlatılıyor…
Devam ediyor: %1$d%
@@ -434,4 +434,25 @@
Tamamlandı! Dosyayı açmak için dokunun.
Süresi dolmuş girdileri gizle
Süresi dolmuş girdiler gizlenecek
+ Veritabanı değişikliklerini kaydetmek için dosya yazma erişimi ver
+ Son veritabanları listesindeki bozuk bağlantıları gizle
+ Bozuk veritabanı bağlantılarını gizle
+ Son veritabanlarının konumlarını göster
+ Son dosyaları göster
+ Veri tabanını anahtar dosyalarının konumunu hatırla
+ Anahtar dosyalarının konumlarını kaydet
+ Veri tabanlarının konumlarını hatırla
+ Veri tabanlarının konumlarını kaydet
+ Veri tabanını açarken arama iste
+ Hızlı arama
+ Katkı
+ İletişim
+ İki öğeli kimlik doğrulaması (2FA) için istenen bir belirteç oluşturmak için Bir Kerelik Parola yönetimini (HOTP / TOTP) ayarlayın.
+ OTP ayarla
+ Veritabanı dosyası oluşturulamıyor.
+ <strong>Özgürlüğümüzü korumak</strong>, <strong>hataları düzeltmek</strong>, <strong>özellikler eklemek</strong> ve <strong>her zaman etkin olmak</strong> için, <strong>desteğinize</strong> güveniyoruz.
+ Ek ekle
+ Vazgeç
+ Değişikliklerden vazgeç\?
+ Doğrula
\ No newline at end of file
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index e860e6e8f..ea402419c 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -104,7 +104,6 @@
Ніколи
Нічого не знайдено.
Нема програми для опрацювання цього посилання.
- Відкрити останню базу даних :
Не шукати записів з резервного копіювання та кошиків
Пропустити групу \'Резервна копія\' та Кошик серед результатів пошуку
Створення нової бази даних…
@@ -124,7 +123,6 @@
Підкреслення
Непідтримувана версія бази даних.
Верхній регістр
- Ваша карта пам’яті зараз не змонтована на телефоні. Ви не зможете завантажити або створити базу даних.
Версія %1$s
Введіть пароль і/або файл ключа для відкриття бази даних.
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
index 688e72ea1..14addc6ea 100644
--- a/app/src/main/res/values-v21/styles.xml
+++ b/app/src/main/res/values-v21/styles.xml
@@ -28,6 +28,7 @@
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 4adbfa755..984504f38 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -19,7 +19,7 @@
-->
反馈
主页
- Android平台上的KeePass密码管理器
+ Android 平台上基于 KeePass 实现的密码管理器
接受
添加条目
添加群组
@@ -39,7 +39,7 @@
正在解密数据库内容…
设为默认数据库
数字
- KeePassDX © %1$d 是Kunzisoft的一个<strong>开源</strong>和<strong>无广告</strong>软件。
+ KeePassDX © %1$d 是 Kunzisoft 的一个<strong>自由软件</strong>并且<strong>不含广告</strong>。
\n它是根据<strong>GPLv3</strong>许可证分发的,您可在遵循GPL 3或者更高版本的协议下重新发布。Kunzisoft对软件的质量和性能等问题不提供任何形式的担保。
打开已有数据库
访问时间
@@ -103,7 +103,6 @@
从不
没有搜索结果
需要安装网络浏览器才能打开这个URL。
- 最近用过的数据库
正在新建数据库…
正在处理…
移除
@@ -121,10 +120,9 @@
下划线
不支持的数据库版本。
大写
- 请挂载内存卡以新建或加载数据库。
输入密码和/或密钥文件来解锁你的数据库。
-\n
-\n记得在每次更改后将数据库文件备份至安全的地方。
+\n
+\n记得在每次做出更改后,将数据库文件备份至安全的地方。
- 5秒
- 10秒
@@ -173,7 +171,7 @@
粘贴
取消
显示密码
- 删除已保存生物识别密钥
+ 删除已保存的与生物识别相关的密钥
只读
可修改
搜索时忽略备份条目
@@ -222,7 +220,7 @@
其他
键盘
魔法键盘
- 写保护(只读模式)
+ 写入保护(只读模式)
默认以只读方式打开数据库
下载
贡献
@@ -235,18 +233,18 @@
避免在数据库中保存编码格式外字符的密码(未识别的字符将转换为同一字符)。
群组在前
回收站在末尾
- 确定不用密码解锁?
- 确认使用空密钥吗?
+ 确定不使用密码保护?
+ 确认不使用加密密钥吗?
版本%1$s
支持生物识别设置,但并未启用生物识别。
打开生物识别对话框以解锁数据库
加密密码已保存
- 不能读取生物识别密钥,请删除所有生物密钥,并重新录入。
+ 不能读取生物识别密钥,请删除所有生物识别密钥,并重新录入。
无法识别生物识别信息
生物识别错误:%1$s
当前数据库无密码。
设为默认的填充服务
- 启用自动填充功能,以便捷地在其他程序中填写信息
+ 启用自动填充功能,以快速填写其他应用中的表单
密码生成长度
设置生成密码的默认长度
密码字符集
@@ -258,8 +256,8 @@
生物识别解锁
通过生物识别解锁数据库
删除加密密钥
- 删除所有与生物相关的加密密钥
- 要删除所有生物识别密钥吗?
+ 删除所有与生物识别相关的密钥
+ 要删除所有与生物识别相关的密钥吗?
无法启动此功能。
你的Android版本%1$s无法满足程序对系统版本%2$s的要求。
找不到所需的硬件。
@@ -311,16 +309,16 @@
将主密钥与生物识别信息关联,以快速解锁数据库。
编辑此条目
使用自定义字段编辑条。自定义字段可以在不同的条目间引用。
- 为记录新建强密码。
- 依据表格中的标准生成新密码,并将密码与条目关联起来,永不忘记。
+ 新建一个强密码
+ 依据表单中的标准进行简单的定义,随机为该条目生成一个强密码,不在担心忘记安全密码。
添加自定义字段
添加一个新的字段并添加为其添加一个值,此时可以选择是否保护该字段及其值。
解锁数据库
- 为数据库开启写保护(只读)
- 在会话中改变打开模式。
-\n
-\n“写保护(只读)”将阻止对数据库的任何修改。
-\n“可编辑(可写)”让添加、删除或者修改元素。
+ 数据库启用写入保护(只读)
+ 更改会话的打开模式。
+\n
+\n“写入保护(只读)”可防止对数据库的意外更改。
+\n“可编辑(可写)”允许您添加、删除或者修改元素。
复制字段
已复制的字段可以粘贴到任何地方。
\n
@@ -331,21 +329,21 @@
选择条目和群组的排序方式。
参与开发
帮助增加稳定性,安全性并添加更多的功能。
- 不同于大多数的密码管理程序,无论您是使用免费版本还是付费版本的KeePassDX,这都是一款<strong>没有广告</strong>,<strong>基于copylefted版权协议的免费软件</strong>,同样的本软件的任何版本也不会收集您的个人信息。
- 通过购买高级版本,您将解锁全部<strong>主题样式</strong>,重要的是,您会为<strong>社区项目的进行</strong>提供的帮助
- 此<strong>主题样式</strong>现在已经可用,感谢慷慨相助。
- 为继续建设此自由项目,我们需要<strong>捐助。</strong>
- 这个特性目前<strong>仍在开发中</strong>,<strong>捐助</strong>将使这个特性在未来变得可用。
+ 不同于大多数的密码管理程序,无论您是使用免费版本还是付费版本的 KeePassDX,这都是一款<strong>没有广告</strong>,<strong>基于 copylefted 版权协议的自由软件</strong>。同时,本软件的任何版本都不会收集您的任何个人信息。
+ 通过购买高级版本,您将解锁全部<strong>主题样式</strong>,重要的是,您会为<strong>社区项目的进行</strong>提供帮助
+ 此<strong>主题样式</strong>已可用,感谢您的慷慨相助。
+ 为继续建设此自由项目让其保持活跃,我们需要您的<strong>捐赠。</strong>
+ 此功能目前<strong>仍在开发中</strong>,<strong>捐助</strong>将使该功能很快变得可用。
通过购买<strong>专业</strong>版,
通过<strong>贡献</strong>,
- 您的留言,鼓励了开发人员开发<strong>新特性</strong>并<strong>修复程序缺陷</strong>。
+ 您的留言,是对开发人员添加<strong>新功能</strong>及<strong>修复 bugs</strong> 的鼓励。
非常感谢您的捐助和贡献。
我们正在努力的研发并尽快发布新特性。
别忘了更新程序。
选择模式
不要终止程序…
按返回键以锁定
- 在点按根屏幕上的后退按钮时锁定数据库
+ 点击屏幕底部的返回键时锁定数据库
关闭程序时清空剪贴板
清除通知时锁定数据库
回收站
@@ -397,7 +395,7 @@
数字位数
算法
一次性密码
- 一次性密码密钥错误。
+ 错误的一次性密码密钥。
至少需要设置一个凭据。
不能将群组复制到这里。
密钥必须是BASE32格式。
@@ -409,7 +407,7 @@
安全设置
主密钥设置
数据库包含重复UUID。
- 通过验证此对话框,KeePassDX将解决这个问题(通过给重复项生成新的UUID)并继续。
+ 通过为重复项生成新的UUID以继续解决问题?
数据库开启
使用设备的剪贴板来复制输入字段
使用高级解锁轻松打开数据库
@@ -423,7 +421,7 @@
建议修改主密钥(以天为单位)
强制修改
要求修改主密钥(以天为单位)
- 下次强制修改
+ 下次强制更新修改
下次强制修改主密钥(一次)
默认用户名
自定义数据库颜色
@@ -435,27 +433,27 @@
保存数据库
清空回收站
正在执行命令……
- 确认要永久删除选中的条目吗?
+ 是否永久删除选中的条目?
请先输入密码,再点击生物识别按钮。
回收站(组)
自动保存数据库
- 在进行重要操作后自动保存数据库(仅在编辑模式下有效)
+ 在每次执行重要操作后保存数据库(仅在编辑模式下有效)
密钥库未正确地初始化。
附件
恢复历史记录
删除历史记录
自动键操作
- 填入用户名或密码后直接登录
+ 填充条目后直接登录
下载%1$s
正在初始化…
- 进行中:%1$d%
+ 进行中:%1$d%
正在完成…
完成!点击打开文件。
隐藏过期条目
过期条目将被隐藏
联系我们
贡献
- 为了<strong>保持我们的自由</strong>,<strong>修复错误</strong>,<strong>添加功能</strong>和<strong>始终保持活跃</strong>,我们期待您的 <strong>贡献</strong>。
+ 为了<strong>维持我们的自由</strong>、<strong>修复 bugs</strong>、<strong>添加更多功能</strong>以及<strong>始终保持项目活跃</strong>,我们期待您的<strong>贡献</strong>。
快速搜索
打开数据库时询问是否进行搜索
数据库保存的路径
@@ -465,4 +463,11 @@
隐藏已损坏的数据库路径
在最近的数据库列表中隐藏已损坏的数据库的链接
授予软件文件读写访问权限以保存数据库更改
+ 设置一次性密码管理(HOTP / TOTP)以生成请求的用于双重身份验证(2FA)的令牌。
+ 设置一次性密码
+ 丢弃
+ 无法创建数据库文件。
+ 添加附件
+ 放弃更改?
+ 验证
\ No newline at end of file
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 923eb5065..e73e7a775 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -102,7 +102,6 @@
從不
沒有搜索結果
沒有這個鏈結的處理程式。
- 最近打開的資料庫:
創建新資料庫中…
工作中…
移除
@@ -120,7 +119,6 @@
強調
不支援的資料庫版本。
大寫
- 你的SD卡目前尚未安裝在您的設備上。你將無法讀或創建您的資料庫。
輸入密碼和/或一個密鑰檔來解鎖你的資料庫.
- 5秒
diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml
index 9fb0a4825..e95e9514f 100644
--- a/app/src/main/res/values/donottranslate.xml
+++ b/app/src/main/res/values/donottranslate.xml
@@ -41,6 +41,7 @@
https://github.com/Kunzisoft/KeePassDX/wiki/Magikeyboard
https://github.com/Kunzisoft/KeePassDX/wiki/Clipboard
https://github.com/Kunzisoft/KeePassDX/wiki/Autofill
+ https://github.com/Kunzisoft/KeePassDX/wiki/File-Manager-and-Sync
--,--`--,{@
@@ -77,6 +78,8 @@
true
lock_database_back_root_key
false
+ lock_database_show_button_key
+ true
password_length_key
list_password_generator_options_key
hide_password_key
@@ -116,6 +119,7 @@
autofill_explanation_key
settings_autofill_enable_key
false
+ settings_autofill_key
keyboard_selection_entry_key
false
keyboard_notification_entry_key
@@ -130,6 +134,8 @@
true
keyboard_key_sound_key
false
+ autofill_auto_search_key
+ true
settings_advanced_unlock_key
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3367183dd..e721610a6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -118,6 +118,7 @@
The passwords do not match.
\"Transformation rounds\" too high. Setting to 2147483648.
Each string must have a field name.
+ This label already exists.
Enter a positive whole number in the \"Length\" field.
Could not enable autofill service.
You can not move a group into itself.
@@ -198,7 +199,6 @@
Install a web browser to open this URL.
Open existing database
Create new database
- Recent databases
Don\'t search through backup entries
Omits \"Backup\" and \"Recycle bin\" groups from search results
Quick search
@@ -253,7 +253,7 @@
Warning
Avoid password characters outside of text encoding format in database file (unrecognized chars are converted to the same letter).
Grant file write access to save database changes
- Mount the memory card to create or load a database.
+ Access to the file revoked by the file manager
Continue without password unlocking protection?
Continue without encryption key?
Permanently delete selected nodes?
@@ -283,6 +283,7 @@
Sign in with KeePassDX
Enable autofilling to quickly fill out forms in other apps
Set default autofill service
+ Autofill settings
Generated password size
Sets default size of the generated passwords
Password characters
@@ -298,6 +299,8 @@
Lock the database when the screen is off
Press \'Back\' to lock
Lock the database when the user clicks the back button on the root screen
+ Show lock button
+ Displays the lock button in the user interface
Advanced unlock
Use advanced unlocking to open a database more easily
Biometric unlocking
@@ -377,6 +380,8 @@
\"Go\" key action after pressing a \"Field\" key
Vibratory keypresses
Audible keypresses
+ Auto search
+ Automatically suggest search results from the web domain or applicationId
Allow no master key
Enable the \"Open\" button if no credentials are selected
Delete password
diff --git a/app/src/main/res/values/style_black.xml b/app/src/main/res/values/style_black.xml
new file mode 100644
index 000000000..ea00d18f7
--- /dev/null
+++ b/app/src/main/res/values/style_black.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 00517cb8e..d6a5c54eb 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -134,60 +134,6 @@
- @style/KeepassDXStyle.Expanded.Title
- @style/KeepassDXStyle.Collapsed.Title
-
@@ -203,13 +149,6 @@
- @color/background_night
-
-
-
-
-
-
-
-
-
-
+
+
+
+