commit b4d447c4b6285c7e27ea52cc842546d9a3c9bc2e
parent 76191f008c2a5f5d0c67681cc973274164fbbce8
Author: Harrison Oglesby <oglesby.harrison@gmail.com>
Date: Wed, 22 Oct 2025 17:29:33 +0000
Bug 1990024 - Create FenixSettingsIndexer r=android-reviewers,petru
Differential Revision: https://phabricator.services.mozilla.com/D266932
Diffstat:
6 files changed, 153 insertions(+), 13 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/DefaultFenixSettingsIndexer.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/DefaultFenixSettingsIndexer.kt
@@ -0,0 +1,35 @@
+/* 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/. */
+
+package org.mozilla.fenix.settings.settingssearch
+
+/**
+ * Indexes Settings preferences for the Settings Search screen.
+ */
+class DefaultFenixSettingsIndexer : SettingsIndexer {
+ private val settings: MutableList<SettingsSearchItem> = mutableListOf()
+
+ /**
+ * Index all settings.
+ */
+ override fun indexAllSettings() {
+ settings.clear()
+ // index settings
+ }
+
+ /**
+ * Get settings filtered by query.
+ *
+ * @param query Query [String] to filter by.
+ * @return List of [SettingsSearchItem]s that match the query.
+ */
+ override fun getSettingsWithQuery(query: String): List<SettingsSearchItem> {
+ if (query.isBlank()) return emptyList()
+
+ return settings.filter { item ->
+ item.title.contains(query, ignoreCase = true) ||
+ item.summary.contains(query, ignoreCase = true)
+ }.toList()
+ }
+}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsIndexer.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsIndexer.kt
@@ -0,0 +1,23 @@
+/* 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/. */
+
+package org.mozilla.fenix.settings.settingssearch
+
+/**
+ * This interface provides a static methods for indexing settings and querying the index.
+ */
+interface SettingsIndexer {
+ /**
+ * Indexes all settings in the app.
+ */
+ fun indexAllSettings()
+
+ /**
+ * Get all settings that match the query.
+ *
+ * @param query The query to search for.
+ * @return A list of [SettingsSearchItem]s that match the query.
+ */
+ fun getSettingsWithQuery(query: String): List<SettingsSearchItem>
+}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchFragment.kt
@@ -25,16 +25,12 @@ class SettingsSearchFragment : Fragment() {
lateinit var settingsSearchStore: SettingsSearchStore
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- settingsSearchStore = buildSettingsSearchStore()
- }
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View = content {
+ settingsSearchStore = buildSettingsSearchStore()
(activity as? AppCompatActivity)?.supportActionBar?.hide()
FirefoxTheme {
SettingsSearchScreen(
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchMiddleware.kt
@@ -12,12 +12,18 @@ import mozilla.components.lib.state.MiddlewareContext
* [Middleware] for the settings search screen.
*
* @param initialDependencies [Dependencies] for the middleware.
+ * @property fenixSettingsIndexer [SettingsIndexer] to use for indexing and querying settings.
*/
class SettingsSearchMiddleware(
initialDependencies: Dependencies,
+ val fenixSettingsIndexer: SettingsIndexer = DefaultFenixSettingsIndexer(),
) : Middleware<SettingsSearchState, SettingsSearchAction> {
var dependencies = initialDependencies
+ init {
+ fenixSettingsIndexer.indexAllSettings()
+ }
+
override fun invoke(
context: MiddlewareContext<SettingsSearchState, SettingsSearchAction>,
next: (SettingsSearchAction) -> Unit,
@@ -27,14 +33,22 @@ class SettingsSearchMiddleware(
when (action) {
is SettingsSearchAction.SearchQueryUpdated -> {
next(action)
-
- if (action.query.isNotBlank()) {
+ val store = context.store as SettingsSearchStore
+ val results = fenixSettingsIndexer.getSettingsWithQuery(action.query)
+ if (results.isEmpty()) {
store.dispatch(SettingsSearchAction.NoResultsFound(action.query))
+ } else {
+ store.dispatch(
+ SettingsSearchAction.SearchResultsLoaded(
+ query = action.query,
+ results = results,
+ ),
+ )
}
}
else -> {
next(action)
- // no op
+ // no op in middleware layer
}
}
}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchStore.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchStore.kt
@@ -39,9 +39,13 @@ private fun reduce(state: SettingsSearchState, action: SettingsSearchAction): Se
}
}
is SettingsSearchAction.NoResultsFound -> {
- SettingsSearchState.NoSearchResults(
- searchQuery = action.query,
- )
+ if (action.query.isBlank()) {
+ SettingsSearchState.Default
+ } else {
+ SettingsSearchState.NoSearchResults(
+ searchQuery = action.query,
+ )
+ }
}
is SettingsSearchAction.SearchResultsLoaded -> {
SettingsSearchState.SearchInProgress(
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchMiddlewareTest.kt
@@ -27,15 +27,21 @@ class SettingsSearchMiddlewareTest {
private fun buildMiddleware(): SettingsSearchMiddleware {
return SettingsSearchMiddleware(
- SettingsSearchMiddleware.Companion.Dependencies(
+ initialDependencies = SettingsSearchMiddleware.Companion.Dependencies(
context,
),
+ fenixSettingsIndexer = TestSettingsIndexer(),
)
}
@Test
fun `WHEN the settings search query is updated and results are not found THEN the state is updated`() {
- val middleware = buildMiddleware()
+ val middleware = SettingsSearchMiddleware(
+ SettingsSearchMiddleware.Companion.Dependencies(
+ context,
+ ),
+ fenixSettingsIndexer = EmptyTestSettingsIndexer(),
+ )
val capture = CaptureActionsMiddleware<SettingsSearchState, SettingsSearchAction>()
val query = "test"
val store = SettingsSearchStore(
@@ -51,4 +57,66 @@ class SettingsSearchMiddlewareTest {
assert(store.state is SettingsSearchState.NoSearchResults)
assert(store.state.searchQuery == query)
}
+
+ @Test
+ fun `WHEN the settings search query is updated and results are found THEN the state is updated`() {
+ val middleware = buildMiddleware()
+ val capture = CaptureActionsMiddleware<SettingsSearchState, SettingsSearchAction>()
+ val query = "test"
+ val store = SettingsSearchStore(
+ middleware = listOf(
+ middleware,
+ capture,
+ ),
+ )
+
+ store.dispatch(SettingsSearchAction.SearchQueryUpdated(query))
+ store.waitUntilIdle()
+ capture.assertLastAction(SettingsSearchAction.SearchResultsLoaded::class)
+ assert(store.state is SettingsSearchState.SearchInProgress)
+ assert(store.state.searchQuery == query)
+ assert(store.state.searchResults == testList)
+ }
+}
+
+val testList = listOf(
+ SettingsSearchItem(
+ title = "Search Engine",
+ summary = "Set your preferred search engine for browsing.",
+ preferenceKey = "search_engine_main",
+ breadcrumbs = listOf("Search", "Default Search Engine"),
+ ),
+ SettingsSearchItem(
+ title = "Advanced Settings",
+ summary = "", // Empty or blank summary
+ preferenceKey = "advanced_stuff",
+ breadcrumbs = listOf("Developer", "Experiments"),
+ ),
+ SettingsSearchItem(
+ title = "Do not collect usage data",
+ summary = "", // Empty or blank summary
+ preferenceKey = "do_not_collect_data",
+ breadcrumbs = listOf("Privacy", "Usage Data"),
+ ),
+)
+
+class TestSettingsIndexer : SettingsIndexer {
+
+ override fun indexAllSettings() {
+ // no op
+ }
+
+ override fun getSettingsWithQuery(query: String): List<SettingsSearchItem> {
+ return testList
+ }
+}
+
+class EmptyTestSettingsIndexer : SettingsIndexer {
+ override fun indexAllSettings() {
+ // no op
+ }
+
+ override fun getSettingsWithQuery(query: String): List<SettingsSearchItem> {
+ return emptyList()
+ }
}