diff options
author | Fabian Henneke <fabian@henneke.me> | 2020-04-15 17:22:44 +0200 |
---|---|---|
committer | Harsh Shandilya <me@msfjarvis.dev> | 2020-04-15 22:47:41 +0530 |
commit | 7cd6f1d1cf78f60cf187d23469934c83915c778d (patch) | |
tree | 158fc49a875058be00674782f4c1894562d80fdc | |
parent | 441b4d3b682824cf20200287c80ccc61f5e0bdef (diff) |
Add a switch between Fuzzy and StrictDomain mode to Autofill search view
3 files changed, 80 insertions, 60 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt index 0901f8d9..57a1f21a 100644 --- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt +++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillFilterActivity.kt @@ -111,78 +111,82 @@ class AutofillFilterView : AppCompatActivity() { supportActionBar?.hide() bindUI() + updateSearch() setResult(RESULT_CANCELED) } private fun bindUI() { - val recyclerAdapter = SearchableRepositoryAdapter( - R.layout.oreo_autofill_filter_row, - ::PasswordViewHolder) { item -> - val file = item.file.relativeTo(item.rootDir) - val pathToIdentifier = directoryStructure.getPathToIdentifierFor(file) - val identifier = directoryStructure.getIdentifierFor(file) - val accountPart = directoryStructure.getAccountPartFor(file) - check(identifier != null || accountPart != null) { "At least one of identifier and accountPart should always be non-null" } - title.text = if (identifier != null) { - buildSpannedString { - if (pathToIdentifier != null) - append("$pathToIdentifier/") - bold { underline { append(identifier) } } + with(binding) { + rvPassword.apply { + adapter = SearchableRepositoryAdapter( + R.layout.oreo_autofill_filter_row, + ::PasswordViewHolder + ) { item -> + val file = item.file.relativeTo(item.rootDir) + val pathToIdentifier = directoryStructure.getPathToIdentifierFor(file) + val identifier = directoryStructure.getIdentifierFor(file) + val accountPart = directoryStructure.getAccountPartFor(file) + check(identifier != null || accountPart != null) { "At least one of identifier and accountPart should always be non-null" } + title.text = if (identifier != null) { + buildSpannedString { + if (pathToIdentifier != null) + append("$pathToIdentifier/") + bold { underline { append(identifier) } } + } + } else { + accountPart + } + subtitle.apply { + if (identifier != null && accountPart != null) { + text = accountPart + visibility = View.VISIBLE + } else { + visibility = View.GONE + } + } + }.onItemClicked { _, item -> + decryptAndFill(item) } - } else { - accountPart + layoutManager = LinearLayoutManager(context) } - subtitle.apply { - if (identifier != null && accountPart != null) { - text = accountPart - visibility = View.VISIBLE - } else { - visibility = View.GONE + search.apply { + val initialSearch = + formOrigin.getPrettyIdentifier(applicationContext, untrusted = false) + setText(initialSearch, TextView.BufferType.EDITABLE) + addTextChangedListener { updateSearch() } + } + strictDomainSearch.apply { + visibility = if (formOrigin is FormOrigin.Web) View.VISIBLE else View.GONE + isChecked = formOrigin is FormOrigin.Web + setOnCheckedChangeListener { _, _ -> updateSearch() } + } + shouldMatch.text = getString( + R.string.oreo_autofill_match_with, + formOrigin.getPrettyIdentifier(applicationContext) + ) + model.searchResult.observe(this@AutofillFilterView) { result -> + val list = result.passwordItems + (rvPassword.adapter as SearchableRepositoryAdapter).submitList(list) { + rvPassword.scrollToPosition(0) + } + // Switch RecyclerView out for a "no results" message if the new list is empty and + // the message is not yet shown (and vice versa). + if ((list.isEmpty() && rvPasswordSwitcher.nextView.id == rvPasswordEmpty.id) || + (list.isNotEmpty() && rvPasswordSwitcher.nextView.id == rvPassword.id) + ) { + rvPasswordSwitcher.showNext() } } - }.onItemClicked { _, item -> - decryptAndFill(item) - } - binding.rvPassword.apply { - adapter = recyclerAdapter - layoutManager = LinearLayoutManager(context) } + } - val initialFilter = formOrigin.getPrettyIdentifier(applicationContext, untrusted = false) - binding.search.setText(initialFilter, TextView.BufferType.EDITABLE) - val filterMode = - if (formOrigin is FormOrigin.Web) FilterMode.StrictDomain else FilterMode.Fuzzy + private fun updateSearch() { model.search( - initialFilter, - filterMode = filterMode, + binding.search.text.toString().trim(), + filterMode = if (binding.strictDomainSearch.isChecked) FilterMode.StrictDomain else FilterMode.Fuzzy, searchMode = SearchMode.RecursivelyInSubdirectories, listMode = ListMode.FilesOnly ) - binding.search.addTextChangedListener { - model.search( - it.toString().trim(), - filterMode = FilterMode.Fuzzy, - searchMode = SearchMode.RecursivelyInSubdirectories, - listMode = ListMode.FilesOnly - ) - } - model.searchResult.observe(this) { result -> - val list = result.passwordItems - recyclerAdapter.submitList(list) { - binding.rvPassword.scrollToPosition(0) - } - // Switch RecyclerView out for a "no results" message if the new list is empty and - // the message is not yet shown (and vice versa). - if ((list.isEmpty() && binding.rvPasswordSwitcher.nextView.id == binding.rvPasswordEmpty.id) || - (list.isNotEmpty() && binding.rvPasswordSwitcher.nextView.id == binding.rvPassword.id) - ) - binding.rvPasswordSwitcher.showNext() - } - - binding.shouldMatch.text = getString( - R.string.oreo_autofill_match_with, - formOrigin.getPrettyIdentifier(applicationContext) - ) } private fun decryptAndFill(item: PasswordItem) { diff --git a/app/src/main/res/layout/activity_oreo_autofill_filter.xml b/app/src/main/res/layout/activity_oreo_autofill_filter.xml index 7c8740c3..da965e05 100644 --- a/app/src/main/res/layout/activity_oreo_autofill_filter.xml +++ b/app/src/main/res/layout/activity_oreo_autofill_filter.xml @@ -46,7 +46,7 @@ android:id="@+id/rvPasswordSwitcher" android:layout_width="0dp" android:layout_marginTop="@dimen/activity_vertical_margin" - app:layout_constraintBottom_toTopOf="@id/shouldMatch" + app:layout_constraintBottom_toTopOf="@id/strictDomainSearch" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/searchLayout" @@ -72,6 +72,21 @@ </ViewSwitcher> <Switch + android:id="@+id/strictDomainSearch" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/activity_horizontal_margin" + android:layout_marginTop="@dimen/activity_vertical_margin" + android:layout_marginEnd="@dimen/activity_horizontal_margin" + android:text="@string/oreo_autofill_strict_domain_search" + app:layout_constraintBottom_toTopOf="@id/shouldMatch" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/rvPasswordSwitcher" + app:layout_constraintVertical_bias="1.0" + tools:text="Phishing-resistant search"/> + + <Switch android:id="@+id/shouldMatch" android:layout_width="0dp" android:layout_height="wrap_content" @@ -82,7 +97,7 @@ app:layout_constraintBottom_toTopOf="@id/shouldClear" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/rvPasswordSwitcher" + app:layout_constraintTop_toBottomOf="@id/strictDomainSearch" app:layout_constraintVertical_bias="1.0" tools:text="Match with example.org" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7f22dc87..f0ba9048 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -250,6 +250,7 @@ <string name="folder_icon_hint">Folder icon</string> <!-- Oreo Autofill --> + <string name="oreo_autofill_strict_domain_search">Phishing-resistant search</string> <string name="oreo_autofill_match_with">Match with %1$s</string> <string name="oreo_autofill_matches_clear_existing">Clear existing matches</string> <string name="oreo_autofill_filter_no_results">No results.</string> |