tor-browser

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

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:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt | 15++++++++++-----
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/ToolbarShortcutPreference.kt | 6++++++
Mmobile/android/fenix/app/src/main/res/values/strings.xml | 2++
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddlewareTest.kt | 103++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
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, )