1
0
Fork 0

For #7087 - Add SearchView to Logins Fragment

master
ekager 2020-03-06 00:12:55 -08:00 committed by Emily Kager
parent d5f4444447
commit 709bf6f627
6 changed files with 73 additions and 8 deletions

View File

@ -6,9 +6,13 @@ package org.mozilla.fenix.settings.logins
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.EditorInfo
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@ -47,6 +51,11 @@ class SavedLoginsFragment : Fragment() {
showToolbar(getString(R.string.preferences_passwords_saved_logins))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -56,7 +65,8 @@ class SavedLoginsFragment : Fragment() {
savedLoginsStore = StoreProvider.get(this) {
SavedLoginsFragmentStore(
SavedLoginsFragmentState(
items = listOf()
items = listOf(),
filteredItems = listOf()
)
)
}
@ -75,6 +85,25 @@ class SavedLoginsFragment : Fragment() {
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.login_list, menu)
val searchItem = menu.findItem(R.id.search)
val searchView: SearchView = searchItem.actionView as SearchView
searchView.imeOptions = EditorInfo.IME_ACTION_DONE
searchView.queryHint = getString(R.string.preferences_passwords_saved_logins_search)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
savedLoginsStore.dispatch(SavedLoginsFragmentAction.FilterLogins(newText))
return false
}
})
}
/**
* If we pause this fragment, we want to pop users back to reauth
*/

View File

@ -38,14 +38,19 @@ class SavedLoginsFragmentStore(initialState: SavedLoginsFragmentState) :
* Actions to dispatch through the `SavedLoginsStore` to modify `SavedLoginsFragmentState` through the reducer.
*/
sealed class SavedLoginsFragmentAction : Action {
data class FilterLogins(val newText: String?) : SavedLoginsFragmentAction()
data class UpdateLogins(val list: List<SavedLoginsItem>) : SavedLoginsFragmentAction()
}
/**
* The state for the Saved Logins Screen
* @property items List of logins to display
* @property items Source of truth of list of logins
* @property items Filtered (or not) list of logins to display
*/
data class SavedLoginsFragmentState(val items: List<SavedLoginsItem>) : State
data class SavedLoginsFragmentState(
val items: List<SavedLoginsItem>,
val filteredItems: List<SavedLoginsItem>
) : State
/**
* The SavedLoginsState Reducer.
@ -55,6 +60,16 @@ private fun savedLoginsStateReducer(
action: SavedLoginsFragmentAction
): SavedLoginsFragmentState {
return when (action) {
is SavedLoginsFragmentAction.UpdateLogins -> state.copy(items = action.list)
is SavedLoginsFragmentAction.UpdateLogins -> state.copy(
items = action.list,
filteredItems = action.list
)
is SavedLoginsFragmentAction.FilterLogins -> {
if (action.newText.isNullOrBlank()) {
state.copy(filteredItems = state.items)
} else {
state.copy(filteredItems = state.items.filter { it.url.contains(action.newText) })
}
}
}
}

View File

@ -71,6 +71,6 @@ class SavedLoginsView(
fun update(state: SavedLoginsFragmentState) {
view.saved_logins_list.isVisible = state.items.isNotEmpty()
view.saved_passwords_empty_view.isVisible = state.items.isEmpty()
loginsAdapter.submitList(state.items)
loginsAdapter.submitList(state.filteredItems)
}
}

View File

@ -9,7 +9,7 @@
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
android:minHeight="?android:attr/listPreferredItemHeight">
<ImageView
android:id="@+id/favicon_image"
@ -28,7 +28,6 @@
android:id="@+id/domainView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginEnd="12dp"
android:layout_weight="1"
android:ellipsize="middle"
@ -37,9 +36,11 @@
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?primaryText"
app:layout_constraintBottom_toTopOf="@id/userView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/favicon_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="mozilla.org" />
<TextView
@ -47,7 +48,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginBottom="4dp"
android:layout_weight="1"
android:ellipsize="middle"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@ -58,5 +58,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/favicon_image"
app:layout_constraintTop_toBottomOf="@id/domainView"
app:layout_constraintVertical_chainStyle="packed"
tools:text="mozilla.org" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/search"
android:icon="@drawable/ic_search"
android:title="@string/preferences_passwords_saved_logins_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:iconTint="?primaryText"
android:contentDescription="@string/preferences_passwords_saved_logins_search"
app:showAsAction="ifRoom|collapseActionView" />
</menu>

View File

@ -6,6 +6,7 @@
<style name="NormalThemeBase" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<!-- Android system styling -->
<item name="searchViewStyle">@style/SearchViewStyle</item>
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
<item name="android:progressBarStyleHorizontal">@style/progressBarStyleHorizontal</item>
@ -101,6 +102,7 @@
<style name="PrivateThemeBase" parent="Theme.MaterialComponents.NoActionBar.Bridge">
<!-- Android system styling -->
<item name="searchViewStyle">@style/SearchViewStyle</item>
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
<item name="android:progressBarStyleHorizontal">@style/progressBarStyleHorizontal</item>
@ -416,4 +418,8 @@
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
<style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
<item name="searchHintIcon">@null</item>
</style>
</resources>