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

View File

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

View File

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

View File

@@ -25,15 +25,18 @@ package com.kunzisoft.keepass.database.search
class SearchParameters { class SearchParameters {
var searchQuery: String = "" var searchQuery: String = ""
var caseSensitive = false
var excludeExpired = false
var searchInTitles = true var searchInTitles = true
var searchInUserNames = true var searchInUsernames = true
var searchInPasswords = false var searchInPasswords = false
var searchInUrls = true var searchInUrls = true
var searchInNotes = true var searchInNotes = true
var searchInOTP = false var searchInOTP = false
var searchInOther = true var searchInOther = true
var searchInUUIDs = false var searchInUUIDs = false
var searchInTags = true var searchInTags = false
var searchInTemplates = 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.Database
import com.kunzisoft.keepass.database.element.Group import com.kunzisoft.keepass.database.element.Group
import com.kunzisoft.keepass.database.search.SearchHelper import com.kunzisoft.keepass.database.search.SearchHelper
import com.kunzisoft.keepass.database.search.SearchParameters
class GroupViewModel: ViewModel() { class GroupViewModel: ViewModel() {
@@ -71,12 +72,12 @@ class GroupViewModel: ViewModel() {
} }
fun loadGroupFromSearch(database: Database?, fun loadGroupFromSearch(database: Database?,
searchQuery: String, searchParameters: SearchParameters,
omitBackup: Boolean) { omitBackup: Boolean) {
IOActionTask( IOActionTask(
{ {
database?.createVirtualGroupFromSearch( database?.createVirtualGroupFromSearch(
searchQuery, searchParameters,
omitBackup, omitBackup,
SearchHelper.MAX_SEARCH_ENTRY SearchHelper.MAX_SEARCH_ENTRY
) )

View File

@@ -95,135 +95,10 @@
android:orientation="horizontal" /> android:orientation="horizontal" />
</androidx.appcompat.widget.Toolbar> </androidx.appcompat.widget.Toolbar>
<LinearLayout <com.kunzisoft.keepass.view.SearchFiltersView
android:id="@+id/search_filters"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" 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>
</FrameLayout> </FrameLayout>
</com.google.android.material.appbar.AppBarLayout> </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>