mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Distinct block lists for AppId and WebDomain
This commit is contained in:
@@ -406,7 +406,7 @@ class Database {
|
|||||||
|
|
||||||
fun createVirtualGroupFromSearch(searchInfo: SearchInfo,
|
fun createVirtualGroupFromSearch(searchInfo: SearchInfo,
|
||||||
max: Int = Integer.MAX_VALUE): Group? {
|
max: Int = Integer.MAX_VALUE): Group? {
|
||||||
if (searchInfo.isNull())
|
if (searchInfo.containsOnlyNullValues())
|
||||||
return null
|
return null
|
||||||
return mSearchHelper?.createVirtualGroupWithSearchResult(this, searchInfo.toString(), SearchParameters().apply {
|
return mSearchHelper?.createVirtualGroupWithSearchResult(this, searchInfo.toString(), SearchParameters().apply {
|
||||||
searchInTitles = false
|
searchInTitles = false
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
|||||||
var applicationId: String? = null
|
var applicationId: String? = null
|
||||||
var webDomain: String? = null
|
var webDomain: String? = null
|
||||||
|
|
||||||
var genericInfo: String? = null
|
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
|
|
||||||
private constructor(parcel: Parcel) {
|
private constructor(parcel: Parcel) {
|
||||||
@@ -19,8 +17,6 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
|||||||
applicationId = if (readAppId.isNullOrEmpty()) null else readAppId
|
applicationId = if (readAppId.isNullOrEmpty()) null else readAppId
|
||||||
val readDomain = parcel.readString()
|
val readDomain = parcel.readString()
|
||||||
webDomain = if (readDomain.isNullOrEmpty()) null else readDomain
|
webDomain = if (readDomain.isNullOrEmpty()) null else readDomain
|
||||||
val readGeneric = parcel.readString()
|
|
||||||
genericInfo = if (readGeneric.isNullOrEmpty()) null else readGeneric
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int {
|
||||||
@@ -30,15 +26,14 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
|||||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
parcel.writeString(applicationId ?: "")
|
parcel.writeString(applicationId ?: "")
|
||||||
parcel.writeString(webDomain ?: "")
|
parcel.writeString(webDomain ?: "")
|
||||||
parcel.writeString(genericInfo ?: "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getName(resources: Resources): String {
|
override fun getName(resources: Resources): String {
|
||||||
return applicationId ?: webDomain ?: genericInfo ?: ""
|
return applicationId ?: webDomain ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isNull(): Boolean {
|
fun containsOnlyNullValues(): Boolean {
|
||||||
return applicationId == null && webDomain == null && genericInfo == null
|
return applicationId == null && webDomain == null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@@ -49,7 +44,6 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
|||||||
|
|
||||||
if (applicationId != other.applicationId) return false
|
if (applicationId != other.applicationId) return false
|
||||||
if (webDomain != other.webDomain) return false
|
if (webDomain != other.webDomain) return false
|
||||||
if (genericInfo != other.genericInfo) return false
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -57,12 +51,11 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
|||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = applicationId?.hashCode() ?: 0
|
var result = applicationId?.hashCode() ?: 0
|
||||||
result = 31 * result + (webDomain?.hashCode() ?: 0)
|
result = 31 * result + (webDomain?.hashCode() ?: 0)
|
||||||
result = 31 * result + (genericInfo?.hashCode() ?: 0)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return applicationId ?: webDomain ?: genericInfo ?: ""
|
return applicationId ?: webDomain ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.AutofillBlocklistPreferenceDialogFragmentCompat
|
import com.kunzisoft.keepass.settings.preferencedialogfragment.AutofillBlocklistAppIdPreferenceDialogFragmentCompat
|
||||||
|
import com.kunzisoft.keepass.settings.preferencedialogfragment.AutofillBlocklistWebDomainPreferenceDialogFragmentCompat
|
||||||
|
|
||||||
class AutofillSettingsFragment : PreferenceFragmentCompat() {
|
class AutofillSettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
@@ -39,8 +40,11 @@ class AutofillSettingsFragment : PreferenceFragmentCompat() {
|
|||||||
var dialogFragment: DialogFragment? = null
|
var dialogFragment: DialogFragment? = null
|
||||||
|
|
||||||
when (preference?.key) {
|
when (preference?.key) {
|
||||||
getString(R.string.autofill_blocklist_key) -> {
|
getString(R.string.autofill_application_id_blocklist_key) -> {
|
||||||
dialogFragment = AutofillBlocklistPreferenceDialogFragmentCompat.newInstance(preference.key)
|
dialogFragment = AutofillBlocklistAppIdPreferenceDialogFragmentCompat.newInstance(preference.key)
|
||||||
|
}
|
||||||
|
getString(R.string.autofill_web_domain_blocklist_key) -> {
|
||||||
|
dialogFragment = AutofillBlocklistWebDomainPreferenceDialogFragmentCompat.newInstance(preference.key)
|
||||||
}
|
}
|
||||||
else -> otherDialogFragment = true
|
else -> otherDialogFragment = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.kunzisoft.keepass.model.SearchInfo
|
||||||
|
|
||||||
|
class AutofillBlocklistAppIdPreferenceDialogFragmentCompat
|
||||||
|
: AutofillBlocklistPreferenceDialogFragmentCompat() {
|
||||||
|
|
||||||
|
override fun buildSearchInfoFromString(searchInfoString: String): SearchInfo? {
|
||||||
|
return if (Regex(APPLICATION_ID_REGEX).matches(searchInfoString)) {
|
||||||
|
SearchInfo().apply { this.applicationId = searchInfoString }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// https://gist.github.com/rishabhmhjn/8663966
|
||||||
|
private const val APPLICATION_ID_REGEX = "^(?:[a-zA-Z]+(?:\\d*[a-zA-Z_]*)*)(?:\\.[a-zA-Z]+(?:\\d*[a-zA-Z_]*)*)+\$"
|
||||||
|
|
||||||
|
fun newInstance(key: String): AutofillBlocklistAppIdPreferenceDialogFragmentCompat {
|
||||||
|
val fragment = AutofillBlocklistAppIdPreferenceDialogFragmentCompat()
|
||||||
|
val bundle = Bundle(1)
|
||||||
|
bundle.putString(ARG_KEY, key)
|
||||||
|
fragment.arguments = bundle
|
||||||
|
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,34 +19,37 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.model.SearchInfo
|
import com.kunzisoft.keepass.model.SearchInfo
|
||||||
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.AutofillBlocklistAdapter
|
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.AutofillBlocklistAdapter
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.Comparator
|
||||||
|
import kotlin.collections.HashSet
|
||||||
|
|
||||||
class AutofillBlocklistPreferenceDialogFragmentCompat
|
abstract class AutofillBlocklistPreferenceDialogFragmentCompat
|
||||||
: InputPreferenceDialogFragmentCompat(),
|
: InputPreferenceDialogFragmentCompat(),
|
||||||
AutofillBlocklistAdapter.ItemDeletedCallback<SearchInfo> {
|
AutofillBlocklistAdapter.ItemDeletedCallback<SearchInfo> {
|
||||||
|
|
||||||
private var persistedItems = HashSet<SearchInfo>()
|
private var persistedItems = TreeSet<SearchInfo>(
|
||||||
|
Comparator { o1, o2 -> o1.toString().compareTo(o2.toString()) })
|
||||||
|
|
||||||
private var filterAdapter: AutofillBlocklistAdapter<SearchInfo>? = null
|
private var filterAdapter: AutofillBlocklistAdapter<SearchInfo>? = null
|
||||||
|
|
||||||
|
abstract fun buildSearchInfoFromString(searchInfoString: String): SearchInfo?
|
||||||
|
|
||||||
override fun onBindDialogView(view: View) {
|
override fun onBindDialogView(view: View) {
|
||||||
super.onBindDialogView(view)
|
super.onBindDialogView(view)
|
||||||
|
|
||||||
preference.getPersistedStringSet(emptySet()).forEach { searchInfoString ->
|
preference.getPersistedStringSet(emptySet()).forEach { searchInfoString ->
|
||||||
persistedItems.add(SearchInfo().apply { genericInfo = searchInfoString })
|
addSearchInfo(searchInfoString)
|
||||||
}
|
}
|
||||||
|
|
||||||
val addItemButton = view.findViewById<View>(R.id.add_item_button)
|
val addItemButton = view.findViewById<View>(R.id.add_item_button)
|
||||||
addItemButton?.setOnClickListener {
|
addItemButton?.setOnClickListener {
|
||||||
persistedItems.add(SearchInfo().apply {
|
addSearchInfo(inputText)
|
||||||
genericInfo = inputText
|
|
||||||
})
|
|
||||||
filterAdapter?.replaceItems(persistedItems.toList())
|
filterAdapter?.replaceItems(persistedItems.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +64,12 @@ class AutofillBlocklistPreferenceDialogFragmentCompat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addSearchInfo(searchInfoString: String) {
|
||||||
|
val itemToAdd = buildSearchInfoFromString(searchInfoString)
|
||||||
|
if (itemToAdd != null && !itemToAdd.containsOnlyNullValues())
|
||||||
|
persistedItems.add(itemToAdd)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onItemDeleted(item: SearchInfo) {
|
override fun onItemDeleted(item: SearchInfo) {
|
||||||
persistedItems.remove(item)
|
persistedItems.remove(item)
|
||||||
filterAdapter?.replaceItems(persistedItems.toList())
|
filterAdapter?.replaceItems(persistedItems.toList())
|
||||||
@@ -81,16 +90,4 @@ class AutofillBlocklistPreferenceDialogFragmentCompat
|
|||||||
preference.persistStringSet(getStringItems())
|
preference.persistStringSet(getStringItems())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun newInstance(key: String): AutofillBlocklistPreferenceDialogFragmentCompat {
|
|
||||||
val fragment = AutofillBlocklistPreferenceDialogFragmentCompat()
|
|
||||||
val bundle = Bundle(1)
|
|
||||||
bundle.putString(ARG_KEY, key)
|
|
||||||
fragment.arguments = bundle
|
|
||||||
|
|
||||||
return fragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.settings.preferencedialogfragment
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.kunzisoft.keepass.model.SearchInfo
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
class AutofillBlocklistWebDomainPreferenceDialogFragmentCompat
|
||||||
|
: AutofillBlocklistPreferenceDialogFragmentCompat() {
|
||||||
|
|
||||||
|
override fun buildSearchInfoFromString(searchInfoString: String): SearchInfo? {
|
||||||
|
// remove prefix https://
|
||||||
|
val newSearchInfo = searchInfoString.replace(Regex("^.*?://"), "")
|
||||||
|
return if (Regex(WEB_DOMAIN_REGEX).matches(newSearchInfo)) {
|
||||||
|
SearchInfo().apply { webDomain = newSearchInfo }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val WEB_DOMAIN_REGEX = "^(?!://)([a-zA-Z0-9-_]+\\.)*[a-zA-Z0-9][a-zA-Z0-9-_]+\\.[a-zA-Z]{2,11}?\$"
|
||||||
|
|
||||||
|
fun newInstance(key: String): AutofillBlocklistWebDomainPreferenceDialogFragmentCompat {
|
||||||
|
val fragment = AutofillBlocklistWebDomainPreferenceDialogFragmentCompat()
|
||||||
|
val bundle = Bundle(1)
|
||||||
|
bundle.putString(ARG_KEY, key)
|
||||||
|
fragment.arguments = bundle
|
||||||
|
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
android:id="@+id/switch_element"
|
android:id="@+id/switch_element"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="20dp"
|
android:layout_margin="24dp"
|
||||||
android:text="@string/enable"
|
android:text="@string/enable"
|
||||||
android:background="@drawable/background_button_small"
|
android:background="@drawable/background_button_small"
|
||||||
android:textColor="?attr/textColorInverse"
|
android:textColor="?attr/textColorInverse"
|
||||||
@@ -55,18 +55,16 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginStart="@dimen/default_margin"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginLeft="@dimen/default_margin"
|
android:layout_marginLeft="24dp"
|
||||||
android:layout_marginEnd="@dimen/default_margin"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginRight="@dimen/default_margin"
|
android:layout_marginRight="24dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/switch_element"
|
app:layout_constraintTop_toBottomOf="@id/switch_element"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/input_text"
|
android:id="@+id/input_text"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/add_item_button"
|
app:layout_constraintEnd_toStartOf="@+id/add_item_button"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/add_item_button"
|
app:layout_constraintBottom_toBottomOf="@id/add_item_button"
|
||||||
@@ -88,10 +86,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="@dimen/default_margin"
|
android:paddingTop="@dimen/default_margin"
|
||||||
android:paddingStart="@dimen/default_margin"
|
android:paddingStart="24dp"
|
||||||
android:paddingLeft="@dimen/default_margin"
|
android:paddingLeft="24dp"
|
||||||
android:paddingEnd="@dimen/default_margin"
|
android:paddingEnd="24dp"
|
||||||
android:paddingRight="@dimen/default_margin"
|
android:paddingRight="24dp"
|
||||||
app:layout_constraintTop_toBottomOf="@id/add_item_container"
|
app:layout_constraintTop_toBottomOf="@id/add_item_container"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|||||||
@@ -132,7 +132,8 @@
|
|||||||
<bool name="keyboard_key_sound_default" translatable="false">false</bool>
|
<bool name="keyboard_key_sound_default" translatable="false">false</bool>
|
||||||
<string name="autofill_auto_search_key" translatable="false">autofill_auto_search_key</string>
|
<string name="autofill_auto_search_key" translatable="false">autofill_auto_search_key</string>
|
||||||
<bool name="autofill_auto_search_default" translatable="false">true</bool>
|
<bool name="autofill_auto_search_default" translatable="false">true</bool>
|
||||||
<string name="autofill_blocklist_key" translatable="false">autofill_blocklist_key</string>
|
<string name="autofill_application_id_blocklist_key" translatable="false">autofill_application_id_blocklist_key</string>
|
||||||
|
<string name="autofill_web_domain_blocklist_key" translatable="false">autofill_web_domain_blocklist_key</string>
|
||||||
|
|
||||||
<!-- Advanced Unlock Settings -->
|
<!-- Advanced Unlock Settings -->
|
||||||
<string name="settings_advanced_unlock_key" translatable="false">settings_advanced_unlock_key</string>
|
<string name="settings_advanced_unlock_key" translatable="false">settings_advanced_unlock_key</string>
|
||||||
|
|||||||
@@ -380,8 +380,11 @@
|
|||||||
<string name="keyboard_key_vibrate_title">Vibratory keypresses</string>
|
<string name="keyboard_key_vibrate_title">Vibratory keypresses</string>
|
||||||
<string name="keyboard_key_sound_title">Audible keypresses</string>
|
<string name="keyboard_key_sound_title">Audible keypresses</string>
|
||||||
<string name="autofill_auto_search_title">Auto search</string>
|
<string name="autofill_auto_search_title">Auto search</string>
|
||||||
<string name="autofill_auto_search_summary">Automatically suggest search results from the web domain or application Id</string>
|
<string name="autofill_auto_search_summary">Automatically suggest search results from the web domain or application ID</string>
|
||||||
<string name="autofill_blocklist_title">Blocklist</string>
|
<string name="autofill_application_id_blocklist_title">Application block list</string>
|
||||||
|
<string name="autofill_application_id_blocklist_summary">Block list that prevents auto filling of apps</string>
|
||||||
|
<string name="autofill_web_domain_blocklist_title">Web domain block list</string>
|
||||||
|
<string name="autofill_web_domain_blocklist_summary">Block list that prevents auto filling of web domains</string>
|
||||||
<string name="allow_no_password_title">Allow no master key</string>
|
<string name="allow_no_password_title">Allow no master key</string>
|
||||||
<string name="allow_no_password_summary">Enable the \"Open\" button if no credentials are selected</string>
|
<string name="allow_no_password_summary">Enable the \"Open\" button if no credentials are selected</string>
|
||||||
<string name="delete_entered_password_title">Delete password</string>
|
<string name="delete_entered_password_title">Delete password</string>
|
||||||
|
|||||||
@@ -29,7 +29,12 @@
|
|||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/filter">
|
android:title="@string/filter">
|
||||||
<com.kunzisoft.keepass.settings.preference.InputListPreference
|
<com.kunzisoft.keepass.settings.preference.InputListPreference
|
||||||
android:key="@string/autofill_blocklist_key"
|
android:key="@string/autofill_application_id_blocklist_key"
|
||||||
android:title="@string/autofill_blocklist_title"/>
|
android:title="@string/autofill_application_id_blocklist_title"
|
||||||
|
android:summary="@string/autofill_application_id_blocklist_summary"/>
|
||||||
|
<com.kunzisoft.keepass.settings.preference.InputListPreference
|
||||||
|
android:key="@string/autofill_web_domain_blocklist_key"
|
||||||
|
android:title="@string/autofill_web_domain_blocklist_title"
|
||||||
|
android:summary="@string/autofill_web_domain_blocklist_summary"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
Reference in New Issue
Block a user