tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 9b30fe531e76922905753ed61dc7e5b95e0c3b77
parent 58c125b817e5630bb1e5e7b4871810deb25fa820
Author: Harrison Oglesby <oglesby.harrison@gmail.com>
Date:   Thu, 23 Oct 2025 19:12:47 +0000

Bug 1990024 - Create FenixSettingsIndexer r=android-reviewers,petru

Differential Revision: https://phabricator.services.mozilla.com/D266932

Diffstat:
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/DefaultFenixSettingsIndexer.kt | 35+++++++++++++++++++++++++++++++++++
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsIndexer.kt | 23+++++++++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchFragment.kt | 6+-----
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchMiddleware.kt | 20+++++++++++++++++---
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchStore.kt | 10+++++++---
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchMiddlewareTest.kt | 74+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
6 files changed, 154 insertions(+), 14 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( @@ -47,8 +53,70 @@ class SettingsSearchMiddlewareTest { store.dispatch(SettingsSearchAction.SearchQueryUpdated(query)) store.waitUntilIdle() - + capture.assertLastAction(SettingsSearchAction.NoResultsFound::class) 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() + } }