For #7087 - Add SearchView to Logins Fragment
parent
d5f4444447
commit
709bf6f627
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue