commit a49e6d408f5a4e7f09d27065648ee468f1dbf835
parent aff8db9d245cd2abf6eb5c4dd01cd95cf4d7b362
Author: Mugurell <Mugurell@users.noreply.github.com>
Date: Mon, 17 Nov 2025 17:52:51 +0000
Bug 1996643 - part 5 - Migrate from the environment idiom within SettingsSearchStore r=android-reviewers,matt-tighe
Differential Revision: https://phabricator.services.mozilla.com/D272158
Diffstat:
6 files changed, 39 insertions(+), 143 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchAction.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchAction.kt
@@ -17,13 +17,6 @@ sealed interface SettingsSearchAction : Action {
data object Init : SettingsSearchAction
/**
- * Signals a new valid [SettingsSearchEnvironment] has been set.
- *
- * @property environment New [SettingsSearchEnvironment].
- */
- data class EnvironmentRehydrated(val environment: SettingsSearchEnvironment) : SettingsSearchAction
-
- /**
* Signals that the current [SettingsSearchEnvironment] has been cleared.
*/
data object EnvironmentCleared : SettingsSearchAction
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchEnvironment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/settingssearch/SettingsSearchEnvironment.kt
@@ -1,24 +0,0 @@
-/* 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
-
-import android.content.Context
-import androidx.fragment.app.Fragment
-import androidx.navigation.NavController
-
-/**
- * Environment for the [SettingsSearchStore].
- *
- * @property navController [NavController] used for navigation.
- * @property fragment [Fragment] used for lifecycle owner and context for UI operations.
- * @property context [Context] used for various system interactions
- * @property recentSettingsSearchesRepository [RecentSettingsSearchesRepository] used for storing recent searches.
- */
-data class SettingsSearchEnvironment(
- val navController: NavController,
- val fragment: Fragment,
- val context: Context,
- val recentSettingsSearchesRepository: RecentSettingsSearchesRepository,
-)
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
@@ -11,9 +11,9 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.compose.content
-import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.coroutineScope
import androidx.navigation.fragment.findNavController
-import org.mozilla.fenix.components.StoreProvider
+import mozilla.components.lib.state.helpers.StoreProvider.Companion.fragmentStore
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.theme.FirefoxTheme
@@ -49,34 +49,18 @@ class SettingsSearchFragment : Fragment() {
private fun buildSettingsSearchStore(): SettingsSearchStore {
val recentSettingsSearchesRepository = FenixRecentSettingsSearchesRepository(requireContext())
- return StoreProvider.get(this) {
+ return fragmentStore(SettingsSearchState.Default(emptyList()) as SettingsSearchState) {
SettingsSearchStore(
initialState = SettingsSearchState.Default(emptyList()),
middleware = listOf(
SettingsSearchMiddleware(
fenixSettingsIndexer = requireContext().components.settingsIndexer,
- ),
- ),
- )
- }.also {
- it.dispatch(
- SettingsSearchAction.EnvironmentRehydrated(
- environment = SettingsSearchEnvironment(
- fragment = this,
navController = findNavController(),
- context = requireContext(),
recentSettingsSearchesRepository = recentSettingsSearchesRepository,
+ scope = viewLifecycleOwner.lifecycle.coroutineScope,
),
),
)
-
- viewLifecycleOwner.lifecycle.addObserver(
- object : DefaultLifecycleObserver {
- override fun onDestroy(owner: androidx.lifecycle.LifecycleOwner) {
- it.dispatch(SettingsSearchAction.EnvironmentCleared)
- }
- },
- )
- }
+ }.value
}
}
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
@@ -5,9 +5,7 @@
package org.mozilla.fenix.settings.settingssearch
import androidx.core.os.bundleOf
-import androidx.lifecycle.Lifecycle.State.RESUMED
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.NavController
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -18,15 +16,19 @@ import mozilla.components.lib.state.MiddlewareContext
/**
* [Middleware] for the settings search screen.
*
- * @property fenixSettingsIndexer [SettingsIndexer] to use for indexing and querying settings.
- * @property dispatcher [CoroutineDispatcher] to use for performing background tasks.
+ * @param fenixSettingsIndexer [SettingsIndexer] to use for indexing and querying settings.
+ * @param navController [NavController] used for navigation.
+ * @param recentSettingsSearchesRepository [RecentSettingsSearchesRepository] used for storing recent searches.
+ * @param scope [CoroutineScope] used for running long running operations in background.
+ * @param dispatcher [CoroutineDispatcher] to use for performing background tasks.
*/
class SettingsSearchMiddleware(
- val fenixSettingsIndexer: SettingsIndexer,
- val dispatcher: CoroutineDispatcher = Dispatchers.IO,
+ private val fenixSettingsIndexer: SettingsIndexer,
+ private val navController: NavController,
+ private val recentSettingsSearchesRepository: RecentSettingsSearchesRepository,
+ private val scope: CoroutineScope,
+ private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
) : Middleware<SettingsSearchState, SettingsSearchAction> {
- internal var environment: SettingsSearchEnvironment? = null
-
override fun invoke(
context: MiddlewareContext<SettingsSearchState, SettingsSearchAction>,
next: (SettingsSearchAction) -> Unit,
@@ -37,17 +39,7 @@ class SettingsSearchMiddleware(
is SettingsSearchAction.Init -> {
next(action)
fenixSettingsIndexer.indexAllSettings()
- }
- is SettingsSearchAction.EnvironmentRehydrated -> {
- next(action)
- environment = action.environment
- environment?.fragment?.viewLifecycleOwner?.lifecycleScope?.launch {
- observeRecentSearches(store)
- }
- }
- is SettingsSearchAction.EnvironmentCleared -> {
- next(action)
- environment = null
+ scope.launch { observeRecentSearches(store) }
}
is SettingsSearchAction.SearchQueryUpdated -> {
next(action)
@@ -73,17 +65,17 @@ class SettingsSearchMiddleware(
)
val fragmentId = searchItem.preferenceFileInformation.fragmentId
CoroutineScope(dispatcher).launch {
- environment?.recentSettingsSearchesRepository?.addRecentSearchItem(searchItem)
+ recentSettingsSearchesRepository.addRecentSearchItem(searchItem)
}
CoroutineScope(Dispatchers.Main).launch {
- environment?.navController?.navigate(fragmentId, bundle)
+ navController.navigate(fragmentId, bundle)
}
next(action)
}
is SettingsSearchAction.ClearRecentSearchesClicked -> {
next(action)
CoroutineScope(Dispatchers.IO).launch {
- environment?.recentSettingsSearchesRepository?.clearRecentSearches()
+ recentSettingsSearchesRepository.clearRecentSearches()
}
}
else -> {
@@ -99,13 +91,9 @@ class SettingsSearchMiddleware(
* @param store The [SettingsSearchStore] to dispatch the updates to.
*/
private fun observeRecentSearches(store: SettingsSearchStore) {
- environment?.fragment?.viewLifecycleOwner?.run {
- lifecycleScope.launch {
- repeatOnLifecycle(RESUMED) {
- environment?.recentSettingsSearchesRepository?.recentSearches?.collect { recents ->
- store.dispatch(SettingsSearchAction.RecentSearchesUpdated(recents))
- }
- }
+ scope.launch {
+ recentSettingsSearchesRepository.recentSearches.collect { recents ->
+ store.dispatch(SettingsSearchAction.RecentSearchesUpdated(recents))
}
}
}
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
@@ -71,7 +71,6 @@ private fun reduce(state: SettingsSearchState, action: SettingsSearchAction): Se
is SettingsSearchAction.Init,
is SettingsSearchAction.ResultItemClicked,
is SettingsSearchAction.EnvironmentCleared,
- is SettingsSearchAction.EnvironmentRehydrated,
-> state
}
}
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
@@ -15,6 +15,8 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import mozilla.components.support.test.robolectric.testContext
@@ -47,31 +49,25 @@ class SettingsSearchMiddlewareTest {
every { fragment.viewLifecycleOwner } returns lifecycleOwner
}
- private fun buildMiddleware(): SettingsSearchMiddleware {
- return SettingsSearchMiddleware(
- fenixSettingsIndexer = TestSettingsIndexer(),
- dispatcher = coroutineRule.testDispatcher,
- )
- }
+ private fun buildMiddleware(
+ fenixSettingsIndexer: SettingsIndexer = TestSettingsIndexer(),
+ navController: NavController = this.navController,
+ recentSettingsSearchesRepository: RecentSettingsSearchesRepository = this.recentSearchesRepository,
+ scope: CoroutineScope = coroutineRule.scope,
+ dispatcher: CoroutineDispatcher = coroutineRule.testDispatcher,
+ ) = SettingsSearchMiddleware(
+ fenixSettingsIndexer = fenixSettingsIndexer,
+ navController = navController,
+ recentSettingsSearchesRepository = recentSettingsSearchesRepository,
+ scope = scope,
+ dispatcher = dispatcher,
+ )
@Test
fun `WHEN the settings search query is updated and results are not found THEN the state is updated`() {
- val middleware = SettingsSearchMiddleware(
- fenixSettingsIndexer = EmptyTestSettingsIndexer(),
- dispatcher = coroutineRule.testDispatcher,
- )
+ val middleware = buildMiddleware(EmptyTestSettingsIndexer())
val query = "longSample"
val store = SettingsSearchStore(middleware = listOf(middleware))
- store.dispatch(
- SettingsSearchAction.EnvironmentRehydrated(
- environment = SettingsSearchEnvironment(
- fragment = fragment,
- navController = navController,
- context = testContext,
- recentSettingsSearchesRepository = recentSearchesRepository,
- ),
- ),
- )
store.dispatch(SettingsSearchAction.SearchQueryUpdated(query))
assert(store.state is SettingsSearchState.NoSearchResults)
assert(store.state.searchQuery == query)
@@ -84,16 +80,6 @@ class SettingsSearchMiddlewareTest {
val query = "a"
val store = SettingsSearchStore(middleware = listOf(middleware))
store.dispatch(SettingsSearchAction.Init)
- store.dispatch(
- SettingsSearchAction.EnvironmentRehydrated(
- environment = SettingsSearchEnvironment(
- fragment = fragment,
- navController = navController,
- context = testContext,
- recentSettingsSearchesRepository = recentSearchesRepository,
- ),
- ),
- )
store.dispatch(SettingsSearchAction.SearchQueryUpdated(query))
assert(store.state is SettingsSearchState.SearchInProgress)
assert(store.state.searchQuery == query)
@@ -106,16 +92,6 @@ class SettingsSearchMiddlewareTest {
val testItem = testList.first()
store.dispatch(SettingsSearchAction.Init)
- store.dispatch(
- SettingsSearchAction.EnvironmentRehydrated(
- environment = SettingsSearchEnvironment(
- fragment = fragment,
- navController = navController,
- context = testContext,
- recentSettingsSearchesRepository = recentSearchesRepository,
- ),
- ),
- )
store.dispatch(SettingsSearchAction.ResultItemClicked(testItem))
@@ -128,16 +104,6 @@ class SettingsSearchMiddlewareTest {
val middleware = buildMiddleware()
val store = SettingsSearchStore(middleware = listOf(middleware))
val updatedRecents = listOf(testList.first())
- store.dispatch(
- SettingsSearchAction.EnvironmentRehydrated(
- environment = SettingsSearchEnvironment(
- fragment = fragment,
- navController = navController,
- context = testContext,
- recentSettingsSearchesRepository = recentSearchesRepository,
- ),
- ),
- )
store.dispatch(SettingsSearchAction.RecentSearchesUpdated(updatedRecents))
@@ -148,16 +114,6 @@ class SettingsSearchMiddlewareTest {
fun `WHEN ClearRecentSearchesClicked is dispatched THEN store state is updated correctly`() {
val middleware = buildMiddleware()
val store = SettingsSearchStore(middleware = listOf(middleware))
- store.dispatch(
- SettingsSearchAction.EnvironmentRehydrated(
- environment = SettingsSearchEnvironment(
- fragment = fragment,
- navController = navController,
- context = testContext,
- recentSettingsSearchesRepository = recentSearchesRepository,
- ),
- ),
- )
store.dispatch(SettingsSearchAction.ClearRecentSearchesClicked)