mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: Form filling auto search #2204
This commit is contained in:
@@ -4,7 +4,7 @@ KeePassDX(4.2.0)
|
||||
* Dialog to manage missing signature #2152 #2155 #2161 #2160
|
||||
* Capture error #2159
|
||||
* Change Passkey Backup Eligibility & Backup State #2135 #2150 #2212
|
||||
* Search settings #2112 #2181 #2187
|
||||
* Search settings #2112 #2181 #2187 #2204
|
||||
* Autofill refactoring #765 #2196
|
||||
* Small fixes #2157 #2164 #2171 #2122 #2180 #2209 #2214
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.database.exception.RegisterInReadOnlyDatabaseException
|
||||
import com.kunzisoft.keepass.database.helper.SearchHelper
|
||||
import com.kunzisoft.keepass.database.helper.SearchHelper.getSearchParametersFromSearchInfo
|
||||
import com.kunzisoft.keepass.database.search.SearchParameters
|
||||
import com.kunzisoft.keepass.education.GroupActivityEducation
|
||||
import com.kunzisoft.keepass.model.DataTime
|
||||
@@ -173,6 +174,7 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
// Manage group
|
||||
private var mSearchState: SearchState? = null
|
||||
private var mAutoSearch: Boolean = false // To mainly manage keyboard
|
||||
private var mTempSearchInfo: Boolean = false // To manage temp search
|
||||
private var mMainGroupState: GroupState? = null // Group state, not a search
|
||||
private var mRootGroup: Group? = null // Root group in the tree
|
||||
private var mMainGroup: Group? = null // Main group currently in memory
|
||||
@@ -214,6 +216,7 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
private val mOnSearchActionExpandListener = object : MenuItem.OnActionExpandListener {
|
||||
override fun onMenuItemActionExpand(p0: MenuItem): Boolean {
|
||||
searchFiltersView?.visibility = View.VISIBLE
|
||||
searchFiltersView?.showSearchExpandButton(!mTempSearchInfo)
|
||||
searchView?.setOnQueryTextListener(mOnSearchQueryTextListener)
|
||||
searchFiltersView?.onParametersChangeListener = mOnSearchFiltersChangeListener
|
||||
|
||||
@@ -258,6 +261,7 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
|
||||
private fun removeSearch() {
|
||||
mSearchState = null
|
||||
mTempSearchInfo = false
|
||||
intent.removeExtra(AUTO_SEARCH_KEY)
|
||||
if (Intent.ACTION_SEARCH == intent.action) {
|
||||
intent.action = Intent.ACTION_DEFAULT
|
||||
@@ -710,37 +714,34 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
finishNodeAction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the AUTO_SEARCH_KEY in ACTION_SEARCH, return true if AUTO_SEARCH_KEY was present
|
||||
*/
|
||||
private fun transformSearchInfoIntent(intent: Intent) {
|
||||
// To relaunch the activity as ACTION_SEARCH
|
||||
val searchInfo: SearchInfo? = intent.retrieveSearchInfo()
|
||||
val autoSearch = intent.getBooleanExtra(AUTO_SEARCH_KEY, false)
|
||||
intent.removeExtra(AUTO_SEARCH_KEY)
|
||||
if (searchInfo != null && autoSearch) {
|
||||
intent.action = Intent.ACTION_SEARCH
|
||||
intent.putExtra(SearchManager.QUERY, searchInfo.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun manageIntent(intent: Intent?) {
|
||||
intent?.let {
|
||||
if (intent.extras?.containsKey(GROUP_STATE_KEY) == true) {
|
||||
mMainGroupState = intent.getParcelableExtraCompat(GROUP_STATE_KEY)
|
||||
intent.removeExtra(GROUP_STATE_KEY)
|
||||
}
|
||||
// To transform KEY_SEARCH_INFO in ACTION_SEARCH
|
||||
transformSearchInfoIntent(intent)
|
||||
// To get the form filling search as temp search
|
||||
val searchInfo: SearchInfo? = intent.retrieveSearchInfo()
|
||||
val autoSearch = intent.getBooleanExtra(AUTO_SEARCH_KEY, false)
|
||||
// Get search query
|
||||
if (intent.action == Intent.ACTION_SEARCH) {
|
||||
if (searchInfo != null && autoSearch) {
|
||||
mAutoSearch = true
|
||||
val stringQuery = intent.getStringExtra(SearchManager.QUERY)?.trim { it <= ' ' } ?: ""
|
||||
intent.action = Intent.ACTION_DEFAULT
|
||||
intent.removeExtra(SearchManager.QUERY)
|
||||
mSearchState = SearchState(PreferencesUtil.getDefaultSearchParameters(this).apply {
|
||||
searchQuery = stringQuery
|
||||
}, mSearchState?.firstVisibleItem ?: 0)
|
||||
mTempSearchInfo = true
|
||||
searchInfo.getSearchParametersFromSearchInfo(this) {
|
||||
mSearchState = SearchState(
|
||||
searchParameters = it,
|
||||
firstVisibleItem = mSearchState?.firstVisibleItem ?: 0
|
||||
)
|
||||
}
|
||||
} else if (intent.action == Intent.ACTION_SEARCH) {
|
||||
mAutoSearch = true
|
||||
mSearchState = SearchState(
|
||||
searchParameters = PreferencesUtil.getDefaultSearchParameters(this).apply {
|
||||
searchQuery = intent.getStringExtra(SearchManager.QUERY)
|
||||
?.trim { it <= ' ' } ?: ""
|
||||
},
|
||||
firstVisibleItem = mSearchState?.firstVisibleItem ?: 0
|
||||
)
|
||||
} else if (mRequestStartupSearch
|
||||
&& PreferencesUtil.automaticallyFocusSearch(this@GroupActivity)) {
|
||||
// Expand the search view if defined in settings
|
||||
@@ -748,6 +749,8 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
mRequestStartupSearch = false
|
||||
addSearch()
|
||||
}
|
||||
intent.action = Intent.ACTION_DEFAULT
|
||||
intent.removeExtra(SearchManager.QUERY)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,7 +775,7 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
// Assign title
|
||||
if (group?.isVirtual == true) {
|
||||
searchFiltersView?.setNumbers(group.numberOfChildEntries)
|
||||
searchFiltersView?.setCurrentGroupText(mMainGroup?.title ?: "")
|
||||
searchFiltersView?.setCurrentGroupText(mMainGroup?.title ?: getString(R.string.search))
|
||||
searchFiltersView?.availableOther(mDatabase?.allowEntryCustomFields() ?: false)
|
||||
searchFiltersView?.availableApplicationIds(mDatabase?.allowEntryCustomFields() ?: false)
|
||||
searchFiltersView?.availableTags(mDatabase?.allowTags() ?: false)
|
||||
@@ -1150,8 +1153,10 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
|
||||
finishNodeAction()
|
||||
searchView?.setOnQueryTextListener(null)
|
||||
if (!mTempSearchInfo) {
|
||||
searchFiltersView?.saveSearchParameters()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSearchQueryInSearchView(searchQuery: String) {
|
||||
searchView?.setOnQueryTextListener(null)
|
||||
@@ -1215,9 +1220,11 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
if (searchState != null) {
|
||||
it.expandActionView()
|
||||
addSearchQueryInSearchView(searchState.searchParameters.searchQuery)
|
||||
if (mTempSearchInfo.not()) {
|
||||
searchFiltersView?.searchParameters = searchState.searchParameters
|
||||
}
|
||||
}
|
||||
}
|
||||
if (it.isActionViewExpanded) {
|
||||
breadcrumbListView?.visibility = View.GONE
|
||||
searchFiltersView?.visibility = View.VISIBLE
|
||||
|
||||
@@ -53,26 +53,67 @@ object SearchHelper {
|
||||
private fun getConcreteWebDomain(
|
||||
context: Context,
|
||||
webDomain: String?,
|
||||
concreteWebDomain: (String?) -> Unit
|
||||
concreteWebDomain: (searchSubDomains: Boolean, concreteWebDomain: String?) -> Unit
|
||||
) {
|
||||
val domain = webDomain
|
||||
val searchSubDomains = searchSubDomains(context)
|
||||
if (domain != null) {
|
||||
// Warning, web domain can contains IP, don't crop in this case
|
||||
if (searchSubDomains(context)
|
||||
if (searchSubDomains
|
||||
|| Regex(SearchInfo.WEB_IP_REGEX).matches(domain)) {
|
||||
concreteWebDomain.invoke(webDomain)
|
||||
concreteWebDomain.invoke(searchSubDomains, webDomain)
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val publicSuffixList = PublicSuffixList(context)
|
||||
val publicSuffix = publicSuffixList
|
||||
.getPublicSuffixPlusOne(domain).await()
|
||||
withContext(Dispatchers.Main) {
|
||||
concreteWebDomain.invoke(publicSuffix)
|
||||
concreteWebDomain.invoke(false, publicSuffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
concreteWebDomain.invoke(null)
|
||||
concreteWebDomain.invoke(searchSubDomains, null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create search parameters asynchronously from [SearchInfo]
|
||||
*/
|
||||
fun SearchInfo.getSearchParametersFromSearchInfo(
|
||||
context: Context,
|
||||
callback: (SearchParameters) -> Unit
|
||||
) {
|
||||
getConcreteWebDomain(
|
||||
context,
|
||||
webDomain
|
||||
) { searchSubDomains, concreteDomain ->
|
||||
var query = this.toString()
|
||||
if (isDomainSearch && concreteDomain != null)
|
||||
query = concreteDomain
|
||||
callback.invoke(
|
||||
SearchParameters().apply {
|
||||
searchQuery = query
|
||||
allowEmptyQuery = false
|
||||
searchInTitles = false
|
||||
searchInUsernames = false
|
||||
searchInPasswords = false
|
||||
searchInAppIds = isAppIdSearch
|
||||
searchInUrls = isDomainSearch
|
||||
searchByDomain = true
|
||||
searchBySubDomain = searchSubDomains
|
||||
searchInRelyingParty = isPasskeySearch
|
||||
searchInNotes = false
|
||||
searchInOTP = isOTPSearch
|
||||
searchInOther = false
|
||||
searchInUUIDs = false
|
||||
searchInTags = isTagSearch
|
||||
searchInCurrentGroup = false
|
||||
searchInSearchableGroup = true
|
||||
searchInRecycleBin = false
|
||||
searchInTemplates = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,36 +137,10 @@ object SearchHelper {
|
||||
&& !searchInfo.manualSelection
|
||||
&& !searchInfo.containsOnlyNullValues()
|
||||
) {
|
||||
getConcreteWebDomain(
|
||||
context,
|
||||
searchInfo.webDomain
|
||||
) { concreteDomain ->
|
||||
var query = searchInfo.toString()
|
||||
if (searchInfo.isDomainSearch && concreteDomain != null)
|
||||
query = concreteDomain
|
||||
searchInfo.getSearchParametersFromSearchInfo(context) { searchParameters ->
|
||||
// If search provide results
|
||||
database.createVirtualGroupFromSearchInfo(
|
||||
searchParameters = SearchParameters().apply {
|
||||
searchQuery = query
|
||||
allowEmptyQuery = false
|
||||
searchInTitles = false
|
||||
searchInUsernames = false
|
||||
searchInPasswords = false
|
||||
searchInAppIds = searchInfo.isAppIdSearch
|
||||
searchInUrls = searchInfo.isDomainSearch
|
||||
searchByDomain = true
|
||||
searchBySubDomain = searchSubDomains(context)
|
||||
searchInRelyingParty = searchInfo.isPasskeySearch
|
||||
searchInNotes = false
|
||||
searchInOTP = searchInfo.isOTPSearch
|
||||
searchInOther = false
|
||||
searchInUUIDs = false
|
||||
searchInTags = searchInfo.isTagSearch
|
||||
searchInCurrentGroup = false
|
||||
searchInSearchableGroup = true
|
||||
searchInRecycleBin = false
|
||||
searchInTemplates = false
|
||||
},
|
||||
searchParameters = searchParameters,
|
||||
max = MAX_SEARCH_ENTRY
|
||||
)?.let { searchGroup ->
|
||||
if (searchGroup.numberOfChildEntries > 0) {
|
||||
|
||||
@@ -210,10 +210,10 @@ class SearchFiltersView @JvmOverloads constructor(context: Context,
|
||||
searchNumbers.text = SearchHelper.showNumberOfSearchResults(numbers)
|
||||
}
|
||||
|
||||
fun setCurrentGroupText(text: String) {
|
||||
fun setCurrentGroupText(text: String?) {
|
||||
val maxChars = 12
|
||||
searchCurrentGroup.text = when {
|
||||
text.isEmpty() -> context.getString(R.string.current_group)
|
||||
text.isNullOrEmpty() -> context.getString(R.string.current_group)
|
||||
text.length > maxChars -> text.substring(0, maxChars) + "…"
|
||||
else -> text
|
||||
}
|
||||
@@ -257,6 +257,10 @@ class SearchFiltersView @JvmOverloads constructor(context: Context,
|
||||
)
|
||||
}
|
||||
|
||||
fun showSearchExpandButton(show: Boolean) {
|
||||
searchExpandButton.isVisible = show
|
||||
}
|
||||
|
||||
override fun setVisibility(visibility: Int) {
|
||||
when (visibility) {
|
||||
VISIBLE -> {
|
||||
|
||||
@@ -37,6 +37,11 @@
|
||||
android:title="@string/enable_auto_save_database_title"
|
||||
android:summary="@string/enable_auto_save_database_summary"
|
||||
android:defaultValue="@bool/enable_auto_save_database_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/auto_focus_search_key"
|
||||
android:title="@string/auto_focus_search_title"
|
||||
android:summary="@string/auto_focus_search_summary"
|
||||
android:defaultValue="@bool/auto_focus_search_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/enable_keep_screen_on_key"
|
||||
android:title="@string/enable_keep_screen_on_title"
|
||||
@@ -47,22 +52,6 @@
|
||||
android:title="@string/enable_screenshot_mode_title"
|
||||
android:summary="@string/enable_screenshot_mode_summary"
|
||||
android:defaultValue="@bool/enable_screenshot_mode_key_default"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/search">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/auto_focus_search_key"
|
||||
android:title="@string/auto_focus_search_title"
|
||||
android:summary="@string/auto_focus_search_summary"
|
||||
android:defaultValue="@bool/auto_focus_search_default"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/subdomain_search_key"
|
||||
android:title="@string/subdomain_search_title"
|
||||
android:summary="@string/subdomain_search_summary"
|
||||
android:defaultValue="@bool/subdomain_search_default"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
-->
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/general">
|
||||
<SwitchPreferenceCompat
|
||||
android:key="@string/subdomain_search_key"
|
||||
android:title="@string/subdomain_search_title"
|
||||
android:summary="@string/subdomain_search_summary"
|
||||
android:defaultValue="@bool/subdomain_search_default"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/keyboard">
|
||||
<Preference
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Passkeys management #1421
|
||||
* Add KPEX_PASSKEY_FLAG_BE and KPEX_PASSKEY_FLAG_BS flags #2212
|
||||
* Fix form filling auto search #2204
|
||||
* Small fixes #2214
|
||||
@@ -1,3 +1,4 @@
|
||||
* Gestion de Passkeys #1421
|
||||
* Ajout des flags KPEX_PASSKEY_FLAG_BE et KPEX_PASSKEY_FLAG_BS #2212
|
||||
* Correction de la recherche auto du remplissage de formulaire #2204
|
||||
* Petites corrections #2214
|
||||
Reference in New Issue
Block a user