Bug 1880490 - Moving Translations `supportedLanguages`

This patch refactors Translations `supportedLanguages` from `[SessionState.translationsState]`
to `[BrowserState.translationEngine]`  in AC.

* Additionally adds `InitTranslationsBrowserState` to signal populating `[BrowserState.translationEngine]`.
* This patch also makes adjustments to migrates Fenix's `TranslationsDialogBinding` and `TranslationsBinding`
 to also monitor this new store location.
fenix/125.0
ohall-m 4 months ago committed by mergify[bot]
parent bef24c2b0e
commit 4bb2681d5d

@ -5,6 +5,7 @@
package org.mozilla.fenix.browser package org.mozilla.fenix.browser
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import mozilla.components.browser.state.selector.findTab import mozilla.components.browser.state.selector.findTab
@ -15,6 +16,7 @@ import mozilla.components.concept.engine.translate.Language
import mozilla.components.concept.engine.translate.initialFromLanguage import mozilla.components.concept.engine.translate.initialFromLanguage
import mozilla.components.concept.engine.translate.initialToLanguage import mozilla.components.concept.engine.translate.initialToLanguage
import mozilla.components.lib.state.helpers.AbstractBinding import mozilla.components.lib.state.helpers.AbstractBinding
import org.mozilla.fenix.translations.TranslationsFlowState
/** /**
* A binding for observing [TranslationsState] changes * A binding for observing [TranslationsState] changes
@ -36,37 +38,62 @@ class TranslationsBinding(
) : AbstractBinding<BrowserState>(browserStore) { ) : AbstractBinding<BrowserState>(browserStore) {
override suspend fun onState(flow: Flow<BrowserState>) { override suspend fun onState(flow: Flow<BrowserState>) {
flow.mapNotNull { state -> state.findTab(sessionId) }.distinctUntilChangedBy { // Browser level flows
it.translationsState val browserFlow = flow.mapNotNull { state -> state }
}.collect { sessionState -> .distinctUntilChangedBy {
val translationsState = sessionState.translationsState it.translationEngine
}
if (translationsState.isTranslated) { // Session level flows
val fromSelected = translationsState.translationEngineState?.initialFromLanguage( val sessionFlow = flow.mapNotNull { state -> state.findTab(sessionId) }
translationsState.supportedLanguages?.fromLanguages, .distinctUntilChangedBy {
) it.translationsState
val toSelected = translationsState.translationEngineState?.initialToLanguage( }
translationsState.supportedLanguages?.toLanguages,
// Applying the flows together
sessionFlow
.combine(browserFlow) { sessionState, browserState ->
TranslationsFlowState(
sessionState,
browserState,
) )
}
.collect { state ->
// Browser Translations State Behavior (Global)
val browserTranslationsState = state.browserState.translationEngine
val translateFromLanguages =
browserTranslationsState.supportedLanguages?.fromLanguages
val translateToLanguages =
browserTranslationsState.supportedLanguages?.toLanguages
if (fromSelected != null && toSelected != null) { // Session Translations State Behavior (Tab)
val sessionTranslationsState = state.sessionState.translationsState
if (sessionTranslationsState.isTranslated) {
val fromSelected = sessionTranslationsState.translationEngineState?.initialFromLanguage(
translateFromLanguages,
)
val toSelected = sessionTranslationsState.translationEngineState?.initialToLanguage(
translateToLanguages,
)
if (fromSelected != null && toSelected != null) {
onStateUpdated(
true,
true,
fromSelected,
toSelected,
)
}
} else if (sessionTranslationsState.isExpectedTranslate) {
onStateUpdated( onStateUpdated(
true, true,
true, false,
fromSelected, null,
toSelected, null,
) )
} else {
onStateUpdated(false, false, null, null)
} }
} else if (translationsState.isExpectedTranslate) {
onStateUpdated(
true,
false,
null,
null,
)
} else {
onStateUpdated(false, false, null, null)
} }
}
} }
} }

@ -5,17 +5,20 @@
package org.mozilla.fenix.translations package org.mozilla.fenix.translations
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import mozilla.components.browser.state.selector.findTab import mozilla.components.browser.state.selector.findTab
import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.translate.initialFromLanguage import mozilla.components.concept.engine.translate.initialFromLanguage
import mozilla.components.concept.engine.translate.initialToLanguage import mozilla.components.concept.engine.translate.initialToLanguage
import mozilla.components.lib.state.helpers.AbstractBinding import mozilla.components.lib.state.helpers.AbstractBinding
/** /**
* Helper for observing Translation state from [BrowserStore]. * Helper for observing Translation state from both [BrowserState.translationEngine]
* and [TabSessionState.translationsState].
*/ */
class TranslationsDialogBinding( class TranslationsDialogBinding(
browserStore: BrowserStore, browserStore: BrowserStore,
@ -24,17 +27,59 @@ class TranslationsDialogBinding(
private val getTranslatedPageTitle: (localizedFrom: String?, localizedTo: String?) -> String, private val getTranslatedPageTitle: (localizedFrom: String?, localizedTo: String?) -> String,
) : AbstractBinding<BrowserState>(browserStore) { ) : AbstractBinding<BrowserState>(browserStore) {
@Suppress("LongMethod")
override suspend fun onState(flow: Flow<BrowserState>) { override suspend fun onState(flow: Flow<BrowserState>) {
flow.mapNotNull { state -> state.findTab(sessionId) } // Browser level flows
val browserFlow = flow.mapNotNull { state -> state }
.distinctUntilChangedBy {
it.translationEngine
}
// Session level flows
val sessionFlow = flow.mapNotNull { state -> state.findTab(sessionId) }
.distinctUntilChangedBy { .distinctUntilChangedBy {
it.translationsState it.translationsState
} }
.collect { sessionState ->
val translationsState = sessionState.translationsState
// Applying the flows together
sessionFlow
.combine(browserFlow) { sessionState, browserState -> TranslationsFlowState(sessionState, browserState) }
.collect {
state ->
// Browser Translations State Behavior (Global)
val browserTranslationsState = state.browserState.translationEngine
val translateFromLanguages =
browserTranslationsState.supportedLanguages?.fromLanguages
translateFromLanguages?.let {
translationsDialogStore.dispatch(
TranslationsDialogAction.UpdateTranslateFromLanguages(
translateFromLanguages,
),
)
}
val translateToLanguages =
browserTranslationsState.supportedLanguages?.toLanguages
translateToLanguages?.let {
translationsDialogStore.dispatch(
TranslationsDialogAction.UpdateTranslateToLanguages(
translateToLanguages,
),
)
}
// Dispatch engine level errors
if (browserTranslationsState.engineError != null) {
translationsDialogStore.dispatch(
TranslationsDialogAction.UpdateTranslationError(browserTranslationsState.engineError),
)
}
// Session Translations State Behavior (Tab)
val sessionTranslationsState = state.sessionState.translationsState
val fromSelected = val fromSelected =
translationsState.translationEngineState?.initialFromLanguage( sessionTranslationsState.translationEngineState?.initialFromLanguage(
translationsState.supportedLanguages?.fromLanguages, translateFromLanguages,
) )
fromSelected?.let { fromSelected?.let {
@ -46,8 +91,8 @@ class TranslationsDialogBinding(
} }
val toSelected = val toSelected =
translationsState.translationEngineState?.initialToLanguage( sessionTranslationsState.translationEngineState?.initialToLanguage(
translationsState.supportedLanguages?.toLanguages, translateToLanguages,
) )
toSelected?.let { toSelected?.let {
translationsDialogStore.dispatch( translationsDialogStore.dispatch(
@ -71,35 +116,18 @@ class TranslationsDialogBinding(
) )
} }
val translateFromLanguages = translationsState.supportedLanguages?.fromLanguages if (sessionTranslationsState.isTranslateProcessing) {
translateFromLanguages?.let {
translationsDialogStore.dispatch(
TranslationsDialogAction.UpdateTranslateFromLanguages(
translateFromLanguages,
),
)
}
val translateToLanguages = translationsState.supportedLanguages?.toLanguages
translateToLanguages?.let {
translationsDialogStore.dispatch(
TranslationsDialogAction.UpdateTranslateToLanguages(
translateToLanguages,
),
)
}
if (translationsState.isTranslateProcessing) {
updateStoreIfIsTranslateProcessing() updateStoreIfIsTranslateProcessing()
} }
if (translationsState.isTranslated && !translationsState.isTranslateProcessing) { if (sessionTranslationsState.isTranslated && !sessionTranslationsState.isTranslateProcessing) {
updateStoreIfTranslated() updateStoreIfTranslated()
} }
if (translationsState.translationError != null) { // A session error may override a browser error
if (sessionTranslationsState.translationError != null) {
translationsDialogStore.dispatch( translationsDialogStore.dispatch(
TranslationsDialogAction.UpdateTranslationError(translationsState.translationError), TranslationsDialogAction.UpdateTranslationError(sessionTranslationsState.translationError),
) )
} }
} }

@ -25,11 +25,7 @@ class TranslationsDialogStore(
initialState, initialState,
TranslationsDialogReducer::reduce, TranslationsDialogReducer::reduce,
middlewares, middlewares,
) { )
init {
dispatch(TranslationsDialogAction.FetchSupportedLanguages)
}
}
/** /**
* The current state of the Translations bottom sheet dialog. * The current state of the Translations bottom sheet dialog.

@ -0,0 +1,19 @@
/* 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.translations
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.TabSessionState
/**
* Convenience method to create a named pair for the translations flow.
*
* @property sessionState The session or tab state.
* @property browserState The browser or global state.
*/
data class TranslationsFlowState(
val sessionState: TabSessionState,
val browserState: BrowserState,
)

@ -83,7 +83,6 @@ class TranslationsBindingTest {
browserStore.dispatch( browserStore.dispatch(
TranslationsAction.SetSupportedLanguagesAction( TranslationsAction.SetSupportedLanguagesAction(
tabId = tab.id,
supportedLanguages = supportLanguages, supportedLanguages = supportLanguages,
), ),
).joinBlocking() ).joinBlocking()

@ -86,6 +86,7 @@ class TelemetryMiddlewareTest {
val engine: Engine = mockk() val engine: Engine = mockk()
every { engine.enableExtensionProcessSpawning() } just runs every { engine.enableExtensionProcessSpawning() } just runs
every { engine.disableExtensionProcessSpawning() } just runs every { engine.disableExtensionProcessSpawning() } just runs
every { engine.getSupportedTranslationLanguages(any(), any()) } just runs
every { engine.isTranslationsEngineSupported(any(), any()) } just runs every { engine.isTranslationsEngineSupported(any(), any()) } just runs
store = BrowserStore( store = BrowserStore(
middleware = listOf(telemetryMiddleware) + EngineMiddleware.create(engine), middleware = listOf(telemetryMiddleware) + EngineMiddleware.create(engine),

@ -88,7 +88,6 @@ class TranslationsDialogBindingTest {
browserStore.dispatch( browserStore.dispatch(
TranslationsAction.SetSupportedLanguagesAction( TranslationsAction.SetSupportedLanguagesAction(
tabId = tab.id,
supportedLanguages = supportLanguages, supportedLanguages = supportLanguages,
), ),
).joinBlocking() ).joinBlocking()
@ -199,7 +198,6 @@ class TranslationsDialogBindingTest {
val supportedLanguages = TranslationSupport(listOf(fromLanguage), listOf(toLanguage)) val supportedLanguages = TranslationSupport(listOf(fromLanguage), listOf(toLanguage))
browserStore.dispatch( browserStore.dispatch(
TranslationsAction.SetSupportedLanguagesAction( TranslationsAction.SetSupportedLanguagesAction(
tabId = tab.id,
supportedLanguages = supportedLanguages, supportedLanguages = supportedLanguages,
), ),
).joinBlocking() ).joinBlocking()

Loading…
Cancel
Save