Bug 1842249 - Refactor HistoryFragment sync handlers to lib-state

fenix/118.0
MatthewTighe 11 months ago committed by mergify[bot]
parent 7b29febee6
commit f513de5cdb

@ -59,6 +59,7 @@ import org.mozilla.fenix.ext.setTextColor
import org.mozilla.fenix.home.Mode
import org.mozilla.fenix.library.LibraryPageFragment
import org.mozilla.fenix.library.history.state.HistoryNavigationMiddleware
import org.mozilla.fenix.library.history.state.HistorySyncMiddleware
import org.mozilla.fenix.library.history.state.HistoryTelemetryMiddleware
import org.mozilla.fenix.tabstray.Page
import org.mozilla.fenix.utils.allowUndo
@ -97,15 +98,24 @@ class HistoryFragment : LibraryPageFragment<History>(), UserInteractionHandler,
historyStore = StoreProvider.get(this) {
HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(
HistoryNavigationMiddleware(
navController = findNavController(),
openToBrowser = ::openItem,
),
HistoryTelemetryMiddleware(
isInPrivateMode = requireComponents.appStore.state.mode == Mode.Private,
),
),
middleware = if (FeatureFlags.historyFragmentLibStateRefactor) {
listOf(
HistoryNavigationMiddleware(
navController = findNavController(),
openToBrowser = ::openItem,
),
HistoryTelemetryMiddleware(
isInPrivateMode = requireComponents.appStore.state.mode == Mode.Private,
),
HistorySyncMiddleware(
accountManager = requireContext().components.backgroundServices.accountManager,
refreshView = { historyView.historyAdapter.refresh() },
scope = lifecycleScope,
),
)
} else {
listOf()
},
)
}
val historyController: HistoryController = DefaultHistoryController(
@ -361,16 +371,13 @@ class HistoryFragment : LibraryPageFragment<History>(), UserInteractionHandler,
}
private fun openItem(item: History.Regular) {
// This telemetry is recorded by the middleware if the refactor is enabled
if (!FeatureFlags.historyFragmentLibStateRefactor) {
GleanHistory.openedItem.record(
GleanHistory.OpenedItemExtra(
isRemote = item.isRemote,
timeGroup = item.historyTimeGroup.toString(),
isPrivate = (activity as HomeActivity).browsingModeManager.mode == BrowsingMode.Private,
),
)
}
GleanHistory.openedItem.record(
GleanHistory.OpenedItemExtra(
isRemote = item.isRemote,
timeGroup = item.historyTimeGroup.toString(),
isPrivate = (activity as HomeActivity).browsingModeManager.mode == BrowsingMode.Private,
),
)
(activity as HomeActivity).openToBrowserAndLoad(
searchTermOrURL = item.url,

@ -12,6 +12,7 @@ import androidx.paging.LoadState
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import mozilla.components.support.base.feature.UserInteractionHandler
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.ComponentHistoryBinding
import org.mozilla.fenix.ext.components
@ -69,7 +70,11 @@ class HistoryView(
val primaryTextColor = ThemeManager.resolveAttribute(R.attr.textPrimary, context)
binding.swipeRefresh.setColorSchemeColors(primaryTextColor)
binding.swipeRefresh.setOnRefreshListener {
interactor.onRequestSync()
if (FeatureFlags.historyFragmentLibStateRefactor) {
store.dispatch(HistoryFragmentAction.StartSync)
} else {
interactor.onRequestSync()
}
}
}

@ -0,0 +1,51 @@
/* 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.library.history.state
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import mozilla.components.lib.state.Middleware
import mozilla.components.lib.state.MiddlewareContext
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.sync.SyncReason
import org.mozilla.fenix.library.history.HistoryFragmentAction
import org.mozilla.fenix.library.history.HistoryFragmentState
/**
* A [Middleware] for handling Sync side-effects based on [HistoryFragmentAction]s that are dispatched
* to the [HistoryFragmentStore].
*
* @property accountManager The [FxaAccountManager] for handling Sync operations.
* @property refreshView Callback to refresh the view once a Sync is completed.
* @property scope Coroutine scope to launch Sync operations into.
*/
class HistorySyncMiddleware(
private val accountManager: FxaAccountManager,
private val refreshView: () -> Unit,
private val scope: CoroutineScope,
) : Middleware<HistoryFragmentState, HistoryFragmentAction> {
override fun invoke(
context: MiddlewareContext<HistoryFragmentState, HistoryFragmentAction>,
next: (HistoryFragmentAction) -> Unit,
action: HistoryFragmentAction,
) {
next(action)
when (action) {
is HistoryFragmentAction.StartSync -> {
scope.launch {
accountManager.syncNow(
reason = SyncReason.User,
debounce = true,
customEngineSubset = listOf(SyncEngine.History),
)
refreshView()
context.store.dispatch(HistoryFragmentAction.FinishSync)
}
}
else -> Unit
}
}
}

@ -0,0 +1,53 @@
/* 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.library.history.state
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.sync.SyncReason
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.mock
import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.test.rule.runTestOnMain
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.mockito.Mockito.verify
import org.mozilla.fenix.library.history.HistoryFragmentAction
import org.mozilla.fenix.library.history.HistoryFragmentState
import org.mozilla.fenix.library.history.HistoryFragmentStore
class HistorySyncMiddlewareTest {
@get:Rule
val coroutinesTestRule = MainCoroutineRule()
@Test
fun `WHEN sync is started THEN account manager handles sync, the view is refreshed, and the sync is finished`() = runTestOnMain {
var viewIsRefreshed = false
val accountManager = mock<FxaAccountManager>()
val middleware = HistorySyncMiddleware(
accountManager = accountManager,
refreshView = { viewIsRefreshed = true },
scope = this,
)
val store = HistoryFragmentStore(
initialState = HistoryFragmentState.initial,
middleware = listOf(middleware),
)
store.dispatch(HistoryFragmentAction.StartSync).joinBlocking()
store.waitUntilIdle()
assertTrue(viewIsRefreshed)
assertEquals(HistoryFragmentState.Mode.Normal, store.state.mode)
verify(accountManager).syncNow(
reason = SyncReason.User,
debounce = true,
customEngineSubset = listOf(SyncEngine.History),
)
}
}
Loading…
Cancel
Save