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 766cda86d..50dd998f8 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.kt
@@ -307,9 +307,8 @@ class GroupActivity : LockingActivity(),
val searchInfo: SearchInfo? = intent.getParcelableExtra(KEY_SEARCH_INFO)
if (searchInfo != null) {
intent.action = Intent.ACTION_SEARCH
- val searchQuery = searchInfo.webDomain ?: searchInfo.applicationId
intent.removeExtra(KEY_SEARCH_INFO)
- intent.putExtra(SearchManager.QUERY, searchQuery)
+ intent.putExtra(SearchManager.QUERY, searchInfo.toString())
return true
}
return false
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 4a006c620..5cdbf0dd4 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
@@ -406,12 +406,9 @@ class Database {
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, SearchParameters().apply {
+ if (searchInfo.isNull())
+ return null
+ return mSearchHelper?.createVirtualGroupWithSearchResult(this, searchInfo.toString(), SearchParameters().apply {
searchInTitles = false
searchInUserNames = false
searchInPasswords = false
diff --git a/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt b/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt
index 8ad6e99f4..283d9f78c 100644
--- a/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/model/SearchInfo.kt
@@ -1,13 +1,17 @@
package com.kunzisoft.keepass.model
+import android.content.res.Resources
import android.os.Parcel
import android.os.Parcelable
+import com.kunzisoft.keepass.utils.ObjectNameResource
-class SearchInfo : Parcelable {
+class SearchInfo : ObjectNameResource, Parcelable {
var applicationId: String? = null
var webDomain: String? = null
+ var genericInfo: String? = null
+
constructor()
private constructor(parcel: Parcel) {
@@ -15,6 +19,8 @@ class SearchInfo : Parcelable {
applicationId = if (readAppId.isNullOrEmpty()) null else readAppId
val readDomain = parcel.readString()
webDomain = if (readDomain.isNullOrEmpty()) null else readDomain
+ val readGeneric = parcel.readString()
+ genericInfo = if (readGeneric.isNullOrEmpty()) null else readGeneric
}
override fun describeContents(): Int {
@@ -24,6 +30,39 @@ class SearchInfo : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(applicationId ?: "")
parcel.writeString(webDomain ?: "")
+ parcel.writeString(genericInfo ?: "")
+ }
+
+ override fun getName(resources: Resources): String {
+ return applicationId ?: webDomain ?: genericInfo ?: ""
+ }
+
+ fun isNull(): Boolean {
+ return applicationId == null && webDomain == null && genericInfo == null
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as SearchInfo
+
+ if (applicationId != other.applicationId) return false
+ if (webDomain != other.webDomain) return false
+ if (genericInfo != other.genericInfo) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = applicationId?.hashCode() ?: 0
+ result = 31 * result + (webDomain?.hashCode() ?: 0)
+ result = 31 * result + (genericInfo?.hashCode() ?: 0)
+ return result
+ }
+
+ override fun toString(): String {
+ return applicationId ?: webDomain ?: genericInfo ?: ""
}
companion object {
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt
index 96558b1b4..3e560442c 100644
--- a/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/AutofillSettingsFragment.kt
@@ -20,9 +20,11 @@
package com.kunzisoft.keepass.settings
import android.os.Bundle
+import androidx.fragment.app.DialogFragment
+import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
-
import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.settings.preferencedialogfragment.AutofillBlacklistPreferenceDialogFragmentCompat
class AutofillSettingsFragment : PreferenceFragmentCompat() {
@@ -30,4 +32,31 @@ class AutofillSettingsFragment : PreferenceFragmentCompat() {
// Load the preferences from an XML resource
setPreferencesFromResource(R.xml.preferences_autofill, rootKey)
}
+
+ override fun onDisplayPreferenceDialog(preference: Preference?) {
+ var otherDialogFragment = false
+
+ var dialogFragment: DialogFragment? = null
+
+ when (preference?.key) {
+ getString(R.string.autofill_blocklist_key) -> {
+ dialogFragment = AutofillBlacklistPreferenceDialogFragmentCompat.newInstance(preference.key)
+ }
+ else -> otherDialogFragment = true
+ }
+
+ if (dialogFragment != null) {
+ dialogFragment.setTargetFragment(this, 0)
+ dialogFragment.show(parentFragmentManager, TAG_AUTOFILL_PREF_FRAGMENT)
+ }
+ // Could not be handled here. Try with the super method.
+ else if (otherDialogFragment) {
+ super.onDisplayPreferenceDialog(preference)
+ }
+ }
+
+ companion object {
+
+ private const val TAG_AUTOFILL_PREF_FRAGMENT = "TAG_AUTOFILL_PREF_FRAGMENT"
+ }
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/preference/InputListPreference.kt b/app/src/main/java/com/kunzisoft/keepass/settings/preference/InputListPreference.kt
new file mode 100644
index 000000000..21965e957
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/preference/InputListPreference.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.preference
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.DialogPreference
+import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.icons.IconPackChooser
+import java.util.ArrayList
+
+open class InputListPreference @JvmOverloads constructor(context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = R.attr.dialogPreferenceStyle,
+ defStyleRes: Int = defStyleAttr)
+ : DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
+
+ override fun getDialogLayoutResource(): Int {
+ return R.layout.pref_dialog_input_list
+ }
+}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/preferencedialogfragment/AutofillBlacklistPreferenceDialogFragmentCompat.kt b/app/src/main/java/com/kunzisoft/keepass/settings/preferencedialogfragment/AutofillBlacklistPreferenceDialogFragmentCompat.kt
new file mode 100644
index 000000000..454cf7359
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/preferencedialogfragment/AutofillBlacklistPreferenceDialogFragmentCompat.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 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.preferencedialogfragment
+
+import android.os.Bundle
+import android.view.View
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.model.SearchInfo
+import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.AutofillBlacklistAdapter
+
+class AutofillBlacklistPreferenceDialogFragmentCompat
+ : InputPreferenceDialogFragmentCompat(),
+ AutofillBlacklistAdapter.ItemDeletedCallback {
+
+ private var persistedItems = HashSet()
+
+ private var filterAdapter: AutofillBlacklistAdapter? = null
+
+ override fun onBindDialogView(view: View) {
+ super.onBindDialogView(view)
+
+ // TODO persistedItems.add
+
+ val addItemButton = view.findViewById(R.id.add_item_button)
+ addItemButton?.setOnClickListener {
+ persistedItems.add(SearchInfo().apply {
+ genericInfo = inputText
+ })
+ filterAdapter?.replaceItems(persistedItems.toList())
+ }
+
+ val recyclerView = view.findViewById(R.id.pref_dialog_list)
+ recyclerView.layoutManager = LinearLayoutManager(context)
+
+ activity?.let { activity ->
+ filterAdapter = AutofillBlacklistAdapter(activity)
+ filterAdapter?.setItemDeletedCallback(this)
+ recyclerView.adapter = filterAdapter
+ filterAdapter?.replaceItems(persistedItems.toList())
+ }
+ }
+
+ override fun onItemDeleted(item: SearchInfo) {
+ persistedItems.remove(item)
+ filterAdapter?.replaceItems(persistedItems.toList())
+ }
+
+ private fun getStringItems(): Set {
+ val setItems = HashSet()
+ persistedItems.forEach {
+ it.getName(resources).let { item ->
+ setItems.add(item)
+ }
+ }
+ return setItems
+ }
+
+ override fun onDialogClosed(positiveResult: Boolean) {
+ if (positiveResult) {
+ preference.persistStringSet(getStringItems())
+ }
+ }
+
+ companion object {
+
+ fun newInstance(key: String): AutofillBlacklistPreferenceDialogFragmentCompat {
+ val fragment = AutofillBlacklistPreferenceDialogFragmentCompat()
+ val bundle = Bundle(1)
+ bundle.putString(ARG_KEY, key)
+ fragment.arguments = bundle
+
+ return fragment
+ }
+ }
+}
diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/preferencedialogfragment/adapter/AutofillBlacklistAdapter.kt b/app/src/main/java/com/kunzisoft/keepass/settings/preferencedialogfragment/adapter/AutofillBlacklistAdapter.kt
new file mode 100644
index 000000000..7886ba443
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/settings/preferencedialogfragment/adapter/AutofillBlacklistAdapter.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 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.preferencedialogfragment.adapter
+
+import android.content.Context
+import androidx.recyclerview.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+
+import com.kunzisoft.keepass.R
+import com.kunzisoft.keepass.utils.ObjectNameResource
+
+import java.util.ArrayList
+
+class AutofillBlacklistAdapter(private val context: Context)
+ : RecyclerView.Adapter() {
+
+ private val inflater: LayoutInflater = LayoutInflater.from(context)
+
+ val items: MutableList = ArrayList()
+
+ private var itemDeletedCallback: ItemDeletedCallback? = null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlacklistItemViewHolder {
+ val view = inflater.inflate(R.layout.pref_dialog_list_removable_item, parent, false)
+ return BlacklistItemViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: BlacklistItemViewHolder, position: Int) {
+ val item = this.items[position]
+ holder.textItem.text = item.getName(context.resources)
+ holder.deleteButton.setOnClickListener(OnItemDeleteClickListener(item))
+ }
+
+ override fun getItemCount(): Int {
+ return items.size
+ }
+
+ fun replaceItems(items: List) {
+ this.items.clear()
+ this.items.addAll(items)
+ notifyDataSetChanged()
+ }
+
+ private inner class OnItemDeleteClickListener(private val itemClicked: T) : View.OnClickListener {
+
+ override fun onClick(view: View) {
+ itemDeletedCallback?.onItemDeleted(itemClicked)
+ notifyDataSetChanged()
+ }
+ }
+
+ fun setItemDeletedCallback(itemDeletedCallback: ItemDeletedCallback) {
+ this.itemDeletedCallback = itemDeletedCallback
+ }
+
+ interface ItemDeletedCallback {
+ fun onItemDeleted(item: T)
+ }
+
+ class BlacklistItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var textItem: TextView = itemView.findViewById(R.id.pref_dialog_list_text)
+ var deleteButton: ImageView = itemView.findViewById(R.id.pref_dialog_list_delete_button)
+ }
+}
diff --git a/app/src/main/res/layout/pref_dialog_input_list.xml b/app/src/main/res/layout/pref_dialog_input_list.xml
new file mode 100644
index 000000000..1b3ca8eee
--- /dev/null
+++ b/app/src/main/res/layout/pref_dialog_input_list.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/pref_dialog_list_removable_item.xml b/app/src/main/res/layout/pref_dialog_list_removable_item.xml
new file mode 100644
index 000000000..24f079b79
--- /dev/null
+++ b/app/src/main/res/layout/pref_dialog_list_removable_item.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml
index 9c6b93295..6def8bff3 100644
--- a/app/src/main/res/values/donottranslate.xml
+++ b/app/src/main/res/values/donottranslate.xml
@@ -132,6 +132,7 @@
false
autofill_auto_search_key
true
+ autofill_blocklist_key
settings_advanced_unlock_key
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d69fc5be0..30b9b083d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -52,6 +52,7 @@
Add node
Add entry
Add group
+ Add item
File information
Password checkbox
Keyfile checkbox
@@ -230,6 +231,7 @@
Do not kill the app…
Space
Search
+ Filter
Sort
Lowest first ↓
Groups before
@@ -379,6 +381,7 @@
Audible keypresses
Auto search
Automatically suggest search results from the web domain or application Id
+ Blacklist
Allow no master key
Enable the \"Open\" button if no credentials are selected
Delete password
diff --git a/app/src/main/res/xml/preferences_autofill.xml b/app/src/main/res/xml/preferences_autofill.xml
index ca7d0e860..6dc635efc 100644
--- a/app/src/main/res/xml/preferences_autofill.xml
+++ b/app/src/main/res/xml/preferences_autofill.xml
@@ -1,6 +1,6 @@