Add search filters view

This commit is contained in:
J-Jamet
2022-01-31 13:46:17 +01:00
parent 05a52dd482
commit 6a468b339f
8 changed files with 367 additions and 205 deletions

View File

@@ -40,6 +40,7 @@ import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.*
@@ -55,6 +56,7 @@ import com.kunzisoft.keepass.database.element.node.Node
import com.kunzisoft.keepass.database.element.node.NodeId
import com.kunzisoft.keepass.database.element.node.Type
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.search.SearchParameters
import com.kunzisoft.keepass.education.GroupActivityEducation
import com.kunzisoft.keepass.model.GroupInfo
import com.kunzisoft.keepass.model.RegisterInfo
@@ -89,11 +91,8 @@ class GroupActivity : DatabaseLockActivity(),
private var databaseNameContainer: ViewGroup? = null
private var databaseColorView: ImageView? = null
private var databaseNameView: TextView? = null
private var searchContainer: ViewGroup? = null
private var searchAdvanceFiltersContainer: ViewGroup? = null
private var searchExpandButton: ImageView? = null
private var searchNumbers: TextView? = null
private var searchView: SearchView? = null
private var searchFiltersView: SearchFiltersView? = null
private var toolbarBreadcrumb: Toolbar? = null
private var toolbarAction: ToolbarAction? = null
private var numberChildrenView: TextView? = null
@@ -121,34 +120,47 @@ class GroupActivity : DatabaseLockActivity(),
private var mPreviousGroupsIds = mutableListOf<GroupState>()
private var mOldGroupToUpdate: Group? = null
private val mOnSearchActionExpandListener = object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(p0: MenuItem?): Boolean {
toolbarBreadcrumb?.hideByFading()
searchAdvanceFiltersContainer?.visibility = View.GONE
searchContainer?.showByFading()
return true
}
override fun onMenuItemActionCollapse(p0: MenuItem?): Boolean {
searchContainer?.hideByFading()
if (searchAdvanceFiltersContainer?.visibility == View.VISIBLE) {
searchAdvanceFiltersContainer?.visibility = View.INVISIBLE
searchAdvanceFiltersContainer?.collapse()
}
toolbarBreadcrumb?.showByFading()
mSearchGroup = null
loadGroup(mDatabase)
return true
}
}
private val mOnSearchQueryTextListener = object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
loadSearchGroup(query)
if (query != null) {
searchFiltersView?.setQuery(query)
}
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
loadSearchGroup(newText)
if (newText != null) {
searchFiltersView?.setQuery(newText)
}
return true
}
}
private val mOnSearchFiltersChangeListener = object : ((SearchParameters) -> Unit) {
override fun invoke(searchParameters: SearchParameters) {
mGroupViewModel.loadGroupFromSearch(
mDatabase,
searchParameters,
PreferencesUtil.omitBackup(this@GroupActivity)
)
}
}
private val mOnSearchActionExpandListener = object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(p0: MenuItem?): Boolean {
toolbarBreadcrumb?.hideByFading()
searchFiltersView?.isVisible = true
searchView?.setOnQueryTextListener(mOnSearchQueryTextListener)
searchFiltersView?.onParametersChangeListener = mOnSearchFiltersChangeListener
return true
}
override fun onMenuItemActionCollapse(p0: MenuItem?): Boolean {
searchFiltersView?.onParametersChangeListener = null
searchView?.setOnQueryTextListener(null)
searchFiltersView?.isVisible = false
toolbarBreadcrumb?.showByFading()
removeSearch()
loadGroup(mDatabase)
return true
}
}
@@ -178,10 +190,7 @@ class GroupActivity : DatabaseLockActivity(),
databaseNameContainer = findViewById(R.id.database_name_container)
databaseColorView = findViewById(R.id.database_color)
databaseNameView = findViewById(R.id.database_name)
searchContainer = findViewById(R.id.search_container)
searchAdvanceFiltersContainer = findViewById(R.id.search_advance_filters)
searchExpandButton = findViewById(R.id.search_expand)
searchNumbers = findViewById(R.id.search_numbers)
searchFiltersView = findViewById(R.id.search_filters)
toolbarBreadcrumb = findViewById(R.id.toolbar_breadcrumb)
breadcrumbListView = findViewById(R.id.breadcrumb_list)
toolbarAction = findViewById(R.id.toolbar_action)
@@ -259,20 +268,6 @@ class GroupActivity : DatabaseLockActivity(),
savedInstanceState.remove(PREVIOUS_GROUPS_IDS_KEY)
}
// Expand menu with button
searchExpandButton?.setOnClickListener {
searchAdvanceFiltersContainer?.let { advanceSearch ->
val isVisible = advanceSearch.visibility == View.VISIBLE
if (isVisible)
advanceSearch.collapse()
else {
advanceSearch.expand(true,
resources.getDimension(R.dimen.advanced_search_height).toInt()
)
}
}
}
// Initialize the fragment with the list
mGroupFragment =
supportFragmentManager.findFragmentByTag(GROUP_FRAGMENT_TAG) as GroupFragment?
@@ -422,15 +417,12 @@ class GroupActivity : DatabaseLockActivity(),
}
private fun loadGroup(database: Database?) {
loadingView?.showByFading()
when {
Intent.ACTION_SEARCH == intent.action -> {
finishNodeAction()
val searchString =
searchFiltersView?.setQuery(
intent.getStringExtra(SearchManager.QUERY)?.trim { it <= ' ' } ?: ""
mGroupViewModel.loadGroupFromSearch(
database,
searchString,
PreferencesUtil.omitBackup(this)
)
}
mCurrentGroupState == null -> {
@@ -606,7 +598,7 @@ class GroupActivity : DatabaseLockActivity(),
// TODO in real time
// Assign title
if (group?.isVirtual == true) {
searchNumbers?.text = SearchHelper.showNumberOfSearchResults(group.numberOfChildEntries)
searchFiltersView?.setNumbers(SearchHelper.showNumberOfSearchResults(group.numberOfChildEntries))
toolbarBreadcrumb?.navigationIcon = null
} else {
// Add breadcrumb
@@ -1017,7 +1009,6 @@ class GroupActivity : DatabaseLockActivity(),
*/
isIconified = false
setOnQueryTextListener(mOnSearchQueryTextListener)
}
// Expand the search view if defined in settings
if (mRequestStartupSearch
@@ -1042,16 +1033,6 @@ class GroupActivity : DatabaseLockActivity(),
return true
}
private fun loadSearchGroup(query: String?) {
if (query != null) {
mGroupViewModel.loadGroupFromSearch(
mDatabase,
query,
PreferencesUtil.omitBackup(this)
)
}
}
private fun performedNextEducation(
groupActivityEducation: GroupActivityEducation,
menu: Menu
@@ -1176,6 +1157,7 @@ class GroupActivity : DatabaseLockActivity(),
}
private fun removeSearch() {
mSearchGroup = null
intent.removeExtra(AUTO_SEARCH_KEY)
if (Intent.ACTION_SEARCH == intent.action) {
intent.action = Intent.ACTION_DEFAULT

View File

@@ -788,13 +788,11 @@ class Database {
false
}
fun createVirtualGroupFromSearch(searchQuery: String,
fun createVirtualGroupFromSearch(searchParameters: SearchParameters,
omitBackup: Boolean,
max: Int = Integer.MAX_VALUE): Group? {
return mSearchHelper?.createVirtualGroupWithSearchResult(this,
SearchParameters().apply {
this.searchQuery = searchQuery
}, omitBackup, max)
searchParameters,omitBackup, max)
}
fun createVirtualGroupFromSearchInfo(searchInfoString: String,
@@ -804,7 +802,7 @@ class Database {
SearchParameters().apply {
searchQuery = searchInfoString
searchInTitles = true
searchInUserNames = false
searchInUsernames = false
searchInPasswords = false
searchInUrls = true
searchInNotes = true

View File

@@ -144,16 +144,23 @@ class SearchHelper {
fun searchInEntry(entry: Entry,
searchParameters: SearchParameters): Boolean {
val searchQuery = searchParameters.searchQuery
// Entry contains string if the search string is empty
// Not found if the search string is empty
if (searchQuery.isEmpty())
return true
return false
// Exclude entry expired
if (searchParameters.excludeExpired) {
if (entry.isCurrentlyExpires)
return false
}
// Search all strings in the KDBX entry
if (searchParameters.searchInTitles) {
if (checkSearchQuery(entry.title, searchParameters))
return true
}
if (searchParameters.searchInUserNames) {
if (searchParameters.searchInUsernames) {
if (checkSearchQuery(entry.username, searchParameters))
return true
}
@@ -171,7 +178,9 @@ class SearchHelper {
}
if (searchParameters.searchInUUIDs) {
val hexString = UuidUtil.toHexString(entry.nodeId.id)
if (hexString != null && hexString.contains(searchQuery, true))
if (hexString != null
&& hexString.contains(searchQuery, true)
)
return true
}
if (searchParameters.searchInOther) {
@@ -183,6 +192,10 @@ class SearchHelper {
}
}
}
if (searchParameters.searchInTags) {
if (checkSearchQuery(entry.tags.toString(), searchParameters))
return true
}
return false
}
@@ -190,14 +203,12 @@ class SearchHelper {
/*
// TODO Search settings
var regularExpression = false
var ignoreCase = true
var removeAccents = true <- Too much time, to study
var excludeExpired = false
var searchOnlyInCurrentGroup = false
*/
return stringToCheck.isNotEmpty()
&& stringToCheck.contains(
searchParameters.searchQuery, true)
searchParameters.searchQuery, !searchParameters.caseSensitive)
}
}
}

View File

@@ -25,15 +25,18 @@ package com.kunzisoft.keepass.database.search
class SearchParameters {
var searchQuery: String = ""
var caseSensitive = false
var excludeExpired = false
var searchInTitles = true
var searchInUserNames = true
var searchInUsernames = true
var searchInPasswords = false
var searchInUrls = true
var searchInNotes = true
var searchInOTP = false
var searchInOther = true
var searchInUUIDs = false
var searchInTags = true
var searchInTags = false
var searchInTemplates = false
}

View File

@@ -0,0 +1,152 @@
package com.kunzisoft.keepass.view
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.search.SearchParameters
class SearchFiltersView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0)
: LinearLayout(context, attrs, defStyle) {
private var searchContainer: ViewGroup
private var searchAdvanceFiltersContainer: ViewGroup
private var searchExpandButton: ImageView
private var searchNumbers: TextView
private var searchCaseSensitive: CompoundButton
private var searchExpires: CompoundButton
private var searchTitle: CompoundButton
private var searchUsername: CompoundButton
private var searchPassword: CompoundButton
private var searchURL: CompoundButton
private var searchNotes: CompoundButton
private var searchOther: CompoundButton
private var searchUUID: CompoundButton
private var searchTag: CompoundButton
var searchParameters = SearchParameters()
get() {
return field.apply {
this.caseSensitive = searchCaseSensitive.isChecked
this.excludeExpired = !(searchExpires.isChecked)
this.searchInTitles = searchTitle.isChecked
this.searchInUsernames = searchUsername.isChecked
this.searchInPasswords = searchPassword.isChecked
this.searchInUrls = searchURL.isChecked
this.searchInNotes = searchNotes.isChecked
this.searchInOther = searchOther.isChecked
this.searchInUUIDs = searchUUID.isChecked
this.searchInTags = searchTag.isChecked
}
}
private set
var onParametersChangeListener: ((searchParameters: SearchParameters) -> Unit)? = null
init {
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater?
inflater?.inflate(R.layout.view_search_filters, this)
searchContainer = findViewById(R.id.search_container)
searchAdvanceFiltersContainer = findViewById(R.id.search_advance_filters)
searchExpandButton = findViewById(R.id.search_expand)
searchNumbers = findViewById(R.id.search_numbers)
searchCaseSensitive = findViewById(R.id.search_chip_case_sensitive)
searchExpires = findViewById(R.id.search_chip_expires)
searchTitle = findViewById(R.id.search_chip_title)
searchUsername = findViewById(R.id.search_chip_username)
searchPassword = findViewById(R.id.search_chip_password)
searchURL = findViewById(R.id.search_chip_url)
searchNotes = findViewById(R.id.search_chip_note)
searchUUID = findViewById(R.id.search_chip_uuid)
searchOther = findViewById(R.id.search_chip_other)
searchTag = findViewById(R.id.search_chip_tag)
// Expand menu with button
searchExpandButton.setOnClickListener {
val isVisible = searchAdvanceFiltersContainer.visibility == View.VISIBLE
if (isVisible)
searchAdvanceFiltersContainer.collapse()
else {
searchAdvanceFiltersContainer.expand(true,
resources.getDimension(R.dimen.advanced_search_height).toInt()
)
}
}
searchCaseSensitive.setOnCheckedChangeListener { _, isChecked ->
searchParameters.caseSensitive = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchExpires.setOnCheckedChangeListener { _, isChecked ->
searchParameters.excludeExpired = !isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchTitle.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInTitles = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchUsername.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInUsernames = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchPassword.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInPasswords = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchURL.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInUrls = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchNotes.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInNotes = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchUUID.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInUUIDs = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchOther.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInOther = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
searchTag.setOnCheckedChangeListener { _, isChecked ->
searchParameters.searchInTags = isChecked
onParametersChangeListener?.invoke(searchParameters)
}
}
fun setQuery(query: String) {
searchParameters.searchQuery = query
onParametersChangeListener?.invoke(searchParameters)
}
fun setNumbers(stringNumbers: String) {
searchNumbers.text = stringNumbers
}
override fun setVisibility(visibility: Int) {
//super.setVisibility(visibility)
when (visibility) {
View.VISIBLE -> {
searchAdvanceFiltersContainer.visibility = View.GONE
searchContainer.showByFading()
}
else -> {
searchContainer.hideByFading()
if (searchAdvanceFiltersContainer.visibility == View.VISIBLE) {
searchAdvanceFiltersContainer.visibility = View.INVISIBLE
searchAdvanceFiltersContainer.collapse()
}
}
}
}
}

View File

@@ -27,6 +27,7 @@ import com.kunzisoft.keepass.app.database.IOActionTask
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.search.SearchParameters
class GroupViewModel: ViewModel() {
@@ -71,12 +72,12 @@ class GroupViewModel: ViewModel() {
}
fun loadGroupFromSearch(database: Database?,
searchQuery: String,
searchParameters: SearchParameters,
omitBackup: Boolean) {
IOActionTask(
{
database?.createVirtualGroupFromSearch(
searchQuery,
searchParameters,
omitBackup,
SearchHelper.MAX_SEARCH_ENTRY
)

View File

@@ -95,135 +95,10 @@
android:orientation="horizontal" />
</androidx.appcompat.widget.Toolbar>
<LinearLayout
<com.kunzisoft.keepass.view.SearchFiltersView
android:id="@+id/search_filters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/search_container"
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
android:layout_height="?attr/actionBarSize"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/search_numbers"
style="@style/KeepassDXStyle.TextAppearance.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_gravity="center"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
tools:text="3" />
<com.google.android.material.chip.ChipGroup
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/search_expand"
app:layout_constraintStart_toEndOf="@+id/search_numbers"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_case_sensitive"
style="@style/KeepassDXStyle.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/case_sensitive" />
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_expires"
style="@style/KeepassDXStyle.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/entry_expires" />
</com.google.android.material.chip.ChipGroup>
<ImageButton
android:id="@+id/search_expand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="@style/KeepassDXStyle.ImageButton.Simple"
android:src="@drawable/ic_list_white_24dp"
app:tint="?attr/textColorInverse"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="@+id/search_advance_filters"
android:layout_width="match_parent"
android:layout_height="@dimen/advanced_search_height"
android:background="?attr/colorPrimary"
android:visibility="gone">
<com.google.android.material.chip.ChipGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:chipSpacingVertical="16dp"
android:paddingTop="12dp"
android:paddingStart="@dimen/default_margin"
android:paddingLeft="@dimen/default_margin"
android:paddingEnd="@dimen/default_margin"
android:paddingRight="@dimen/default_margin"
android:paddingBottom="@dimen/default_margin">
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_title"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_user_name"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_password"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_url"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_notes"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_other"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/other"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_uuid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_UUID"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_tag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/tags"/>
</com.google.android.material.chip.ChipGroup>
</FrameLayout>
</LinearLayout>
android:layout_height="wrap_content" />
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/search_container"
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
android:layout_height="?attr/actionBarSize"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/search_numbers"
style="@style/KeepassDXStyle.TextAppearance.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_gravity="center"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
tools:text="3" />
<com.google.android.material.chip.ChipGroup
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/search_expand"
app:layout_constraintStart_toEndOf="@+id/search_numbers"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_case_sensitive"
style="@style/KeepassDXStyle.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/case_sensitive" />
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_expires"
style="@style/KeepassDXStyle.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/entry_expires" />
</com.google.android.material.chip.ChipGroup>
<ImageButton
android:id="@+id/search_expand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="@style/KeepassDXStyle.ImageButton.Simple"
android:src="@drawable/ic_list_white_24dp"
app:tint="?attr/textColorInverse"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="@+id/search_advance_filters"
android:layout_width="match_parent"
android:layout_height="@dimen/advanced_search_height"
android:background="?attr/colorPrimary"
android:visibility="gone">
<com.google.android.material.chip.ChipGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:chipSpacingVertical="16dp"
android:paddingTop="12dp"
android:paddingStart="@dimen/default_margin"
android:paddingLeft="@dimen/default_margin"
android:paddingEnd="@dimen/default_margin"
android:paddingRight="@dimen/default_margin"
android:paddingBottom="@dimen/default_margin">
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_title"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_user_name"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_password"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_url"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_notes"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_other"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/other"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_uuid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/entry_UUID"/>
<com.google.android.material.chip.Chip
android:id="@+id/search_chip_tag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
style="@style/KeepassDXStyle.Chip.Filter"
android:text="@string/tags"/>
</com.google.android.material.chip.ChipGroup>
</FrameLayout>
</LinearLayout>