tor-browser

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

commit bdd147ba6aa33bfbccd1e47ababfaeee943ca86a
parent 29ea9091ad03f3a0dd2227729952a313f30f355a
Author: rmalicdem <rmalicdem@mozilla.com>
Date:   Tue, 28 Oct 2025 19:58:16 +0000

Bug 1969066 - Add 'Add bookmark' to simple shortcut toolbar customization r=android-reviewers,android-l10n-reviewers,delphine,Roger

Differential Revision: https://phabricator.services.mozilla.com/D270003

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt | 38++++++++++++++++++++++++++++++--------
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/ToolbarShortcutPreference.kt | 18++++++++++++++++--
Mmobile/android/fenix/app/src/main/res/values/strings.xml | 7+++++++
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddlewareTest.kt | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 115 insertions(+), 10 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 @@ -239,7 +239,9 @@ class BrowserToolbarMiddleware( updateStartBrowserActions(context) updateCurrentPageOrigin(context) - updateEndBrowserActions(context) + environment?.fragment?.viewLifecycleOwner?.lifecycleScope?.launch { + updateEndBrowserActions(context) + } updateEndPageActions(context) environment?.fragment?.viewLifecycleOwner?.lifecycleScope?.launch { updateNavigationActions(context) @@ -669,12 +671,22 @@ class BrowserToolbarMiddleware( ), ) - private fun updateEndBrowserActions(context: MiddlewareContext<BrowserToolbarState, BrowserToolbarAction>) = + private suspend fun updateEndBrowserActions(context: MiddlewareContext<BrowserToolbarState, BrowserToolbarAction>) { + val url = browserStore.state.selectedTab?.content?.url + val isBookmarked = if (url != null) { + withContext(ioDispatcher) { + bookmarksStorage.getBookmarksWithUrl(url).getOrDefault(listOf()).isNotEmpty() + } + } else { + false + } + context.dispatch( BrowserActionsEndUpdated( - buildEndBrowserActions(), + buildEndBrowserActions(isBookmarked), ), - ) + ) + } private fun buildStartPageActions(): List<Action> { return listOf( @@ -738,14 +750,16 @@ class BrowserToolbarMiddleware( } } - private fun buildEndBrowserActions(): List<Action> { + private fun buildEndBrowserActions(isBookmarked: Boolean): List<Action> { val isWideWindow = environment?.fragment?.isWideWindow() == true val isTallWindow = environment?.fragment?.isTallWindow() == true val tabStripEnabled = settings.isTabStripEnabled val shouldUseExpandedToolbar = settings.shouldUseExpandedToolbar val useCustomPrimary = settings.shouldShowToolbarCustomization && !shouldUseExpandedToolbar - val primarySlotAction = mapShortcutToAction(settings.toolbarShortcutKey) - .takeIf { useCustomPrimary } ?: ToolbarAction.NewTab + val primarySlotAction = mapShortcutToAction( + settings.toolbarShortcutKey, + isBookmarked, + ).takeIf { useCustomPrimary } ?: ToolbarAction.NewTab val configs = listOf( ToolbarActionConfig(primarySlotAction) { @@ -1032,6 +1046,7 @@ class BrowserToolbarMiddleware( it.snackbarState is SnackbarState.BookmarkAdded || it.snackbarState is SnackbarState.BookmarkDeleted }.collect { isBookmarked -> + updateEndBrowserActions(context) updateNavigationActions(context) } } @@ -1249,9 +1264,16 @@ class BrowserToolbarMiddleware( companion object { @VisibleForTesting @JvmStatic - internal fun mapShortcutToAction(key: String): ToolbarAction = when (key) { + internal fun mapShortcutToAction( + key: String, + isBookmarked: Boolean = false, + ): ToolbarAction = when (key) { ToolbarShortcutPreference.Keys.NEW_TAB -> ToolbarAction.NewTab ToolbarShortcutPreference.Keys.SHARE -> ToolbarAction.Share + ToolbarShortcutPreference.Keys.BOOKMARK -> when (isBookmarked) { + true -> ToolbarAction.EditBookmark + false -> ToolbarAction.Bookmark + } 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 @@ -39,8 +39,21 @@ class ToolbarShortcutPreference @JvmOverloads constructor( private val options: List<Option> by lazy { listOf( - Option(Keys.NEW_TAB, iconsR.drawable.mozac_ic_plus_24, R.string.home_screen_shortcut_open_new_tab_2), - Option(Keys.SHARE, iconsR.drawable.mozac_ic_share_android_24, R.string.browser_menu_share), + Option( + Keys.NEW_TAB, + iconsR.drawable.mozac_ic_plus_24, + R.string.toolbar_customize_shortcut_new_tab, + ), + Option( + Keys.SHARE, + iconsR.drawable.mozac_ic_share_android_24, + R.string.toolbar_customize_shortcut_share, + ), + Option( + Keys.BOOKMARK, + iconsR.drawable.mozac_ic_bookmark_24, + R.string.toolbar_customize_shortcut_add_bookmark, + ), ) } @@ -171,5 +184,6 @@ class ToolbarShortcutPreference @JvmOverloads constructor( object Keys { const val NEW_TAB = "new_tab" const val SHARE = "share" + const val BOOKMARK = "bookmark" } } diff --git a/mobile/android/fenix/app/src/main/res/values/strings.xml b/mobile/android/fenix/app/src/main/res/values/strings.xml @@ -1138,6 +1138,13 @@ <!-- Preference description indicating the toolbar location preference is disabled when the tab strip is enabled --> <string name="preference_toolbar_pref_disabled_explanation">Address bar must be on top when tab bar is shown.</string> + <!-- New tab shortcut in toolbar customization --> + <string name="toolbar_customize_shortcut_new_tab">Open a new tab</string> + <!-- Share shortcut in toolbar customization --> + <string name="toolbar_customize_shortcut_share">Share</string> + <!-- Add bookmark shortcut in toolbar customization --> + <string name="toolbar_customize_shortcut_add_bookmark">Add bookmark</string> + <!-- App icon Preferences --> <!-- Title for the preference that lets the user pick a new app icon --> <string name="preference_select_app_icon_title">Select App Icon</string> 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 @@ -943,6 +943,8 @@ class BrowserToolbarMiddlewareTest { navController = navController, browsingModeManager = browsingModeManager, ) + mainLooperRule.idle() + val tabCounterButton = toolbarStore.state.displayState.browserActionsEnd[1] as TabCounterAction assertEqualsTabCounterButton(expectedTabCounterButton(2, true), tabCounterButton) val tabCounterMenuItems = (tabCounterButton.onLongClick as CombinedEventAndMenu).menu.items() @@ -979,6 +981,8 @@ class BrowserToolbarMiddlewareTest { navController = navController, browsingModeManager = browsingModeManager, ) + mainLooperRule.idle() + val tabCounterButton = toolbarStore.state.displayState.browserActionsEnd[1] as TabCounterAction assertEqualsTabCounterButton(expectedTabCounterButton(1, false), tabCounterButton) val tabCounterMenuItems = (tabCounterButton.onLongClick as CombinedEventAndMenu).menu.items() @@ -1021,6 +1025,8 @@ class BrowserToolbarMiddlewareTest { navController = navController, browsingModeManager = browsingModeManager, ) + mainLooperRule.idle() + val tabCounterButton = toolbarStore.state.displayState.browserActionsEnd[1] as TabCounterAction assertEqualsTabCounterButton(expectedTabCounterButton(1, true), tabCounterButton) val tabCounterMenuItems = (tabCounterButton.onLongClick as CombinedEventAndMenu).menu.items() @@ -1067,6 +1073,8 @@ class BrowserToolbarMiddlewareTest { navController = navController, browsingModeManager = browsingModeManager, ) + mainLooperRule.idle() + val tabCounterButton = toolbarStore.state.displayState.browserActionsEnd[1] as TabCounterAction assertEqualsTabCounterButton(expectedTabCounterButton(1, true), tabCounterButton) val tabCounterMenuItems = (tabCounterButton.onLongClick as CombinedEventAndMenu).menu.items() @@ -1119,6 +1127,8 @@ class BrowserToolbarMiddlewareTest { navController = navController, browsingModeManager = browsingModeManager, ) + mainLooperRule.idle() + val tabCounterButton = toolbarStore.state.displayState.browserActionsEnd[1] as TabCounterAction assertEqualsTabCounterButton(expectedTabCounterButton(1, true), tabCounterButton) val tabCounterMenuItems = (tabCounterButton.onLongClick as CombinedEventAndMenu).menu.items() @@ -1460,6 +1470,7 @@ class BrowserToolbarMiddlewareTest { browsingModeManager = browsingModeManager, navController = navController, ) + mainLooperRule.idle() val shareButton = toolbarStore.state.displayState.browserActionsEnd[0] as ActionButtonRes assertEquals(expectedShareButton(), shareButton) @@ -1497,6 +1508,7 @@ class BrowserToolbarMiddlewareTest { browsingModeManager = browsingModeManager, navController = navController, ) + mainLooperRule.idle() val shareButton = toolbarStore.state.displayState.browserActionsEnd[0] as ActionButtonRes assertEquals(expectedShareButton(), shareButton) @@ -2737,6 +2749,45 @@ class BrowserToolbarMiddlewareTest { } @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 + val toolbarStore = buildStore() + + val bookmarkButton = toolbarStore.state.displayState.browserActionsEnd[0] as ActionButtonRes + assertEquals(expectedBookmarkButton(Source.AddressBar), bookmarkButton) + } + + @Test + fun `GIVEN simple toolbar use add bookmark shortcut AND the current page is bookmarked WHEN initializing toolbar THEN show ACTIVE EditBookmark in end browser actions`() = runTest { + every { settings.shouldShowToolbarCustomization } returns true + every { settings.toolbarShortcutKey } returns ToolbarShortcutPreference.Keys.BOOKMARK + + val tab = createTab("https://example.com") + val browserStore = BrowserStore( + BrowserState( + tabs = listOf(tab), + selectedTabId = tab.id, + ), + ) + + coEvery { bookmarksStorage.getBookmarksWithUrl(tab.content.url) } returns Result.success( + listOf(mockk(relaxed = true)), + ) + + val middleware = buildMiddleware( + browserStore = browserStore, + bookmarksStorage = bookmarksStorage, + ) + + val toolbarStore = buildStore(middleware) + mainLooperRule.idle() + + val editButton = toolbarStore.state.displayState.browserActionsEnd [0] as ActionButtonRes + assertEquals(expectedEditBookmarkButton(Source.AddressBar), editButton) + } + + @Test fun `mapShortcutToAction maps keys to actions and falls back to NewTab`() { assertEquals( ToolbarAction.NewTab, @@ -2747,6 +2798,17 @@ class BrowserToolbarMiddlewareTest { BrowserToolbarMiddleware.mapShortcutToAction(ToolbarShortcutPreference.Keys.SHARE), ) assertEquals( + ToolbarAction.Bookmark, + BrowserToolbarMiddleware.mapShortcutToAction(ToolbarShortcutPreference.Keys.BOOKMARK), + ) + assertEquals( + ToolbarAction.EditBookmark, + BrowserToolbarMiddleware.mapShortcutToAction( + ToolbarShortcutPreference.Keys.BOOKMARK, + true, + ), + ) + assertEquals( ToolbarAction.NewTab, BrowserToolbarMiddleware.mapShortcutToAction("does_not_exist"), )