commit c70298a84d848402dc075ea900ad0287ea58c990
parent b3e788f9a04b2d775b8a2190283d5fa115777162
Author: rmalicdem <rmalicdem@mozilla.com>
Date: Wed, 29 Oct 2025 19:18:47 +0000
Bug 1969071 - Add 'Translate' to simple shortcut toolbar customization r=android-reviewers,android-l10n-reviewers,delphine,Roger
Differential Revision: https://phabricator.services.mozilla.com/D270004
Diffstat:
4 files changed, 115 insertions(+), 11 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt
@@ -112,8 +112,8 @@ import org.mozilla.fenix.components.toolbar.DisplayActions.NavigateForwardLongCl
import org.mozilla.fenix.components.toolbar.DisplayActions.RefreshClicked
import org.mozilla.fenix.components.toolbar.DisplayActions.ShareClicked
import org.mozilla.fenix.components.toolbar.DisplayActions.StopRefreshClicked
+import org.mozilla.fenix.components.toolbar.DisplayActions.TranslateClicked
import org.mozilla.fenix.components.toolbar.PageEndActionsInteractions.ReaderModeClicked
-import org.mozilla.fenix.components.toolbar.PageEndActionsInteractions.TranslateClicked
import org.mozilla.fenix.components.toolbar.PageOriginInteractions.OriginClicked
import org.mozilla.fenix.components.toolbar.TabCounterInteractions.AddNewPrivateTab
import org.mozilla.fenix.components.toolbar.TabCounterInteractions.AddNewTab
@@ -148,6 +148,7 @@ internal sealed class DisplayActions : BrowserToolbarEvent {
data class AddBookmarkClicked(override val source: Source) : DisplayActions()
data class EditBookmarkClicked(override val source: Source) : DisplayActions()
data class ShareClicked(override val source: Source) : DisplayActions()
+ data object TranslateClicked : DisplayActions()
}
@VisibleForTesting
@@ -174,8 +175,6 @@ internal sealed class PageEndActionsInteractions : BrowserToolbarEvent {
data class ReaderModeClicked(
val isActive: Boolean,
) : PageEndActionsInteractions()
-
- data object TranslateClicked : PageEndActionsInteractions()
}
/**
@@ -731,6 +730,9 @@ class BrowserToolbarMiddleware(
*/
private fun buildEndPageActions(): List<Action> {
val isWideScreen = environment?.fragment?.isWideWindow() == true
+ val tabStripEnabled = settings.isTabStripEnabled
+ val translateShortcutEnabled = settings.toolbarShortcutKey == ToolbarShortcutPreference.Keys.TRANSLATE
+ val shareShortcutEnabled = settings.toolbarShortcutKey == ToolbarShortcutPreference.Keys.SHARE
return listOf(
ToolbarActionConfig(ToolbarAction.ReaderMode) {
@@ -738,10 +740,11 @@ class BrowserToolbarMiddleware(
},
ToolbarActionConfig(ToolbarAction.Translate) {
browserScreenStore.state.pageTranslationStatus.isTranslationPossible &&
- isWideScreen && FxNimbus.features.translations.value().mainFlowToolbarEnabled
+ isWideScreen && FxNimbus.features.translations.value().mainFlowToolbarEnabled &&
+ !(translateShortcutEnabled && !tabStripEnabled)
},
ToolbarActionConfig(ToolbarAction.Share) {
- isWideScreen && !settings.isTabStripEnabled
+ isWideScreen && !tabStripEnabled && !shareShortcutEnabled
},
).filter { config ->
config.isVisible()
@@ -1004,6 +1007,7 @@ class BrowserToolbarMiddleware(
browserScreenStore.observeWhileActive {
distinctUntilChangedBy { it.pageTranslationStatus }
.collect {
+ updateEndBrowserActions(context)
updateEndPageActions(context)
}
}
@@ -1274,6 +1278,7 @@ class BrowserToolbarMiddleware(
true -> ToolbarAction.EditBookmark
false -> ToolbarAction.Bookmark
}
+ ToolbarShortcutPreference.Keys.TRANSLATE -> ToolbarAction.Translate
else -> ToolbarAction.NewTab
}
}
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/ToolbarShortcutPreference.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/ToolbarShortcutPreference.kt
@@ -54,6 +54,11 @@ class ToolbarShortcutPreference @JvmOverloads constructor(
iconsR.drawable.mozac_ic_bookmark_24,
R.string.toolbar_customize_shortcut_add_bookmark,
),
+ Option(
+ Keys.TRANSLATE,
+ iconsR.drawable.mozac_ic_translate_24,
+ R.string.toolbar_customize_shortcut_translate,
+ ),
)
}
@@ -185,5 +190,6 @@ class ToolbarShortcutPreference @JvmOverloads constructor(
const val NEW_TAB = "new_tab"
const val SHARE = "share"
const val BOOKMARK = "bookmark"
+ const val TRANSLATE = "translate"
}
}
diff --git a/mobile/android/fenix/app/src/main/res/values/strings.xml b/mobile/android/fenix/app/src/main/res/values/strings.xml
@@ -1144,6 +1144,8 @@
<string name="toolbar_customize_shortcut_share">Share</string>
<!-- Add bookmark shortcut in toolbar customization -->
<string name="toolbar_customize_shortcut_add_bookmark">Add bookmark</string>
+ <!-- Translate shortcut in toolbar customization. "Translate" is a verb -->
+ <string name="toolbar_customize_shortcut_translate">Translate</string>
<!-- App icon Preferences -->
<!-- Title for the preference that lets the user pick a new app icon -->
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddlewareTest.kt
@@ -150,8 +150,8 @@ import org.mozilla.fenix.components.toolbar.DisplayActions.NavigateForwardLongCl
import org.mozilla.fenix.components.toolbar.DisplayActions.RefreshClicked
import org.mozilla.fenix.components.toolbar.DisplayActions.ShareClicked
import org.mozilla.fenix.components.toolbar.DisplayActions.StopRefreshClicked
+import org.mozilla.fenix.components.toolbar.DisplayActions.TranslateClicked
import org.mozilla.fenix.components.toolbar.PageEndActionsInteractions.ReaderModeClicked
-import org.mozilla.fenix.components.toolbar.PageEndActionsInteractions.TranslateClicked
import org.mozilla.fenix.components.toolbar.PageOriginInteractions.OriginClicked
import org.mozilla.fenix.components.toolbar.TabCounterInteractions.AddNewPrivateTab
import org.mozilla.fenix.components.toolbar.TabCounterInteractions.AddNewTab
@@ -1308,7 +1308,7 @@ class BrowserToolbarMiddlewareTest {
)
val translateButton = toolbarStore.state.displayState.pageActionsEnd[0]
- assertEquals(expectedTranslateButton, translateButton)
+ assertEquals(expectedTranslateButton(), translateButton)
}
@Test
@@ -1337,7 +1337,7 @@ class BrowserToolbarMiddlewareTest {
),
)
var translateButton = toolbarStore.state.displayState.pageActionsEnd[0]
- assertEquals(expectedTranslateButton, translateButton)
+ assertEquals(expectedTranslateButton(), translateButton)
browserScreenStore.dispatch(
PageTranslationStatusUpdated(
@@ -1350,7 +1350,7 @@ class BrowserToolbarMiddlewareTest {
)
translateButton = toolbarStore.state.displayState.pageActionsEnd[0]
assertEquals(
- expectedTranslateButton.copy(state = ActionButton.State.ACTIVE),
+ expectedTranslateButton(isActive = true),
translateButton,
)
}
@@ -1682,7 +1682,7 @@ class BrowserToolbarMiddlewareTest {
assertEquals(
listOf(
expectedReaderModeButton(false),
- expectedTranslateButton,
+ expectedTranslateButton(),
expectedShareButton(),
),
toolbarStore.state.displayState.pageActionsEnd,
@@ -2749,6 +2749,51 @@ class BrowserToolbarMiddlewareTest {
}
@Test
+ fun `GIVEN share shortcut is selected THEN update end page actions without share action`() = runTest {
+ configuration = Configuration().apply {
+ screenHeightDp = 400
+ screenWidthDp = 700
+ }
+ every { mockContext.resources.configuration } returns configuration
+ every { settings.isTabStripEnabled } returns false
+ every { settings.toolbarShortcutKey } returns ToolbarShortcutPreference.Keys.SHARE
+ val browserScreenStore = buildBrowserScreenStore()
+ val middleware = buildMiddleware(appStore, browserScreenStore, browserStore)
+ val toolbarStore = buildStore(middleware, browsingModeManager = browsingModeManager, navController = navController)
+
+ val endPageActions = toolbarStore.state.displayState.pageActionsEnd
+ assertEquals(emptyList<Action>(), endPageActions)
+ }
+
+ @Test
+ fun `GIVEN translate shortcut is selected THEN update end page actions without translate action`() = runTest {
+ configuration = Configuration().apply {
+ screenHeightDp = 400
+ screenWidthDp = 700
+ }
+ every { mockContext.resources.configuration } returns configuration
+ every { settings.isTabStripEnabled } returns false
+ every { settings.toolbarShortcutKey } returns ToolbarShortcutPreference.Keys.TRANSLATE
+ val browserScreenStore = buildBrowserScreenStore()
+ val middleware = buildMiddleware(appStore, browserScreenStore, browserStore)
+ val toolbarStore = buildStore(middleware, browsingModeManager = browsingModeManager, navController = navController)
+
+ browserScreenStore.dispatch(
+ PageTranslationStatusUpdated(
+ PageTranslationStatus(
+ isTranslationPossible = true,
+ isTranslated = false,
+ isTranslateProcessing = false,
+ ),
+ ),
+ )
+
+ val translateButton = toolbarStore.state.displayState.pageActionsEnd[0]
+ assertNotEquals(expectedTranslateButton(), translateButton)
+ assertEquals(expectedShareButton(), translateButton)
+ }
+
+ @Test
fun `GIVEN simple toolbar use add bookmark shortcut AND the current page is not bookmarked WHEN initializing toolbar THEN show Bookmark in end browser actions`() = runTest {
every { settings.shouldShowToolbarCustomization } returns true
every { settings.toolbarShortcutKey } returns ToolbarShortcutPreference.Keys.BOOKMARK
@@ -2788,6 +2833,44 @@ class BrowserToolbarMiddlewareTest {
}
@Test
+ fun `GIVEN simple toolbar use translate shortcut AND current page is not translated WHEN initializing toolbar THEN show Translate in end browser actions`() = runTest {
+ every { settings.shouldShowToolbarCustomization } returns true
+ every { settings.toolbarShortcutKey } returns ToolbarShortcutPreference.Keys.TRANSLATE
+
+ val pageTranslationStatus: PageTranslationStatus = mockk(relaxed = true) {
+ every { isTranslationPossible } returns true
+ every { isTranslated } returns false
+ every { isTranslateProcessing } returns false
+ }
+
+ every { browserScreenState.pageTranslationStatus } returns pageTranslationStatus
+
+ val toolbarStore = buildStore()
+
+ val translateButton = toolbarStore.state.displayState.browserActionsEnd[0] as ActionButtonRes
+ assertEquals(expectedTranslateButton(), translateButton)
+ }
+
+ @Test
+ fun `GIVEN simple toolbar use translate shortcut AND current page is translated WHEN initializing toolbar THEN show ACTIVE Translate in end browser actions`() = runTest {
+ every { settings.shouldShowToolbarCustomization } returns true
+ every { settings.toolbarShortcutKey } returns ToolbarShortcutPreference.Keys.TRANSLATE
+
+ val pageTranslationStatus: PageTranslationStatus = mockk(relaxed = true) {
+ every { isTranslationPossible } returns true
+ every { isTranslated } returns true
+ every { isTranslateProcessing } returns false
+ }
+
+ every { browserScreenState.pageTranslationStatus } returns pageTranslationStatus
+
+ val toolbarStore = buildStore()
+
+ val translateButton = toolbarStore.state.displayState.browserActionsEnd[0] as ActionButtonRes
+ assertEquals(expectedTranslateButton(isActive = true), translateButton)
+ }
+
+ @Test
fun `mapShortcutToAction maps keys to actions and falls back to NewTab`() {
assertEquals(
ToolbarAction.NewTab,
@@ -2809,6 +2892,10 @@ class BrowserToolbarMiddlewareTest {
),
)
assertEquals(
+ ToolbarAction.Translate,
+ BrowserToolbarMiddleware.mapShortcutToAction(ToolbarShortcutPreference.Keys.TRANSLATE),
+ )
+ assertEquals(
ToolbarAction.NewTab,
BrowserToolbarMiddleware.mapShortcutToAction("does_not_exist"),
)
@@ -2893,9 +2980,13 @@ class BrowserToolbarMiddlewareTest {
onLongClick = NavigateBackLongClicked,
)
- private val expectedTranslateButton = ActionButtonRes(
+ private fun expectedTranslateButton(isActive: Boolean = false) = ActionButtonRes(
drawableResId = iconsR.drawable.mozac_ic_translate_24,
contentDescription = R.string.browser_toolbar_translate,
+ state = when (isActive) {
+ true -> ActionButton.State.ACTIVE
+ false -> ActionButton.State.DEFAULT
+ },
onClick = TranslateClicked,
)