[fenix] For https://github.com/mozilla-mobile/fenix/issues/24252 - Rename primaryText...
[gecko.git] / mobile / android / fenix / app / src / main / java / org / mozilla / fenix / customtabs / CustomTabToolbarMenu.kt
blob0986c00554bbee829a4f974bdcbec5ae62040a73
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 package org.mozilla.fenix.customtabs
7 import android.content.Context
8 import android.graphics.Typeface
9 import androidx.annotation.ColorRes
10 import androidx.annotation.VisibleForTesting
11 import androidx.core.content.ContextCompat.getColor
12 import mozilla.components.browser.menu.BrowserMenuBuilder
13 import mozilla.components.browser.menu.BrowserMenuHighlight
14 import mozilla.components.browser.menu.item.BrowserMenuCategory
15 import mozilla.components.browser.menu.item.BrowserMenuDivider
16 import mozilla.components.browser.menu.item.BrowserMenuHighlightableItem
17 import mozilla.components.browser.menu.item.BrowserMenuImageSwitch
18 import mozilla.components.browser.menu.item.BrowserMenuImageText
19 import mozilla.components.browser.menu.item.BrowserMenuItemToolbar
20 import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
21 import mozilla.components.browser.state.selector.findCustomTab
22 import mozilla.components.browser.state.state.CustomTabSessionState
23 import mozilla.components.browser.state.store.BrowserStore
24 import org.mozilla.fenix.R
25 import org.mozilla.fenix.components.toolbar.ToolbarMenu
26 import org.mozilla.fenix.ext.components
27 import org.mozilla.fenix.ext.getStringWithArgSafe
28 import org.mozilla.fenix.ext.settings
29 import org.mozilla.fenix.theme.ThemeManager
30 import java.util.Locale
32 /**
33  * Builds the toolbar object used with the 3-dot menu in the custom tab browser fragment.
34  * @param store reference to the application's [BrowserStore].
35  * @param sessionId ID of the open custom tab session.
36  * @param shouldReverseItems If true, reverse the menu items.
37  * @param onItemTapped Called when a menu item is tapped.
38  */
39 class CustomTabToolbarMenu(
40     private val context: Context,
41     private val store: BrowserStore,
42     private val sessionId: String?,
43     private val shouldReverseItems: Boolean,
44     private val onItemTapped: (ToolbarMenu.Item) -> Unit = {}
45 ) : ToolbarMenu {
47     override val menuBuilder by lazy { BrowserMenuBuilder(menuItems) }
49     /** Gets the current custom tab session */
50     @VisibleForTesting
51     internal val session: CustomTabSessionState? get() = sessionId?.let { store.state.findCustomTab(it) }
52     private val appName = context.getString(R.string.app_name)
54     override val menuToolbar by lazy {
55         val back = BrowserMenuItemToolbar.TwoStateButton(
56             primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_back,
57             primaryContentDescription = context.getString(R.string.browser_menu_back),
58             primaryImageTintResource = primaryTextColor(),
59             isInPrimaryState = {
60                 session?.content?.canGoBack ?: true
61             },
62             secondaryImageTintResource = ThemeManager.resolveAttribute(
63                 R.attr.disabled,
64                 context
65             ),
66             disableInSecondaryState = true,
67             longClickListener = { onItemTapped.invoke(ToolbarMenu.Item.Back(viewHistory = true)) }
68         ) {
69             onItemTapped.invoke(ToolbarMenu.Item.Back(viewHistory = false))
70         }
72         val forward = BrowserMenuItemToolbar.TwoStateButton(
73             primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_forward,
74             primaryContentDescription = context.getString(R.string.browser_menu_forward),
75             primaryImageTintResource = primaryTextColor(),
76             isInPrimaryState = {
77                 session?.content?.canGoForward ?: true
78             },
79             secondaryImageTintResource = ThemeManager.resolveAttribute(
80                 R.attr.disabled,
81                 context
82             ),
83             disableInSecondaryState = true,
84             longClickListener = { onItemTapped.invoke(ToolbarMenu.Item.Forward(viewHistory = true)) }
85         ) {
86             onItemTapped.invoke(ToolbarMenu.Item.Forward(viewHistory = false))
87         }
89         val refresh = BrowserMenuItemToolbar.TwoStateButton(
90             primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_refresh,
91             primaryContentDescription = context.getString(R.string.browser_menu_refresh),
92             primaryImageTintResource = primaryTextColor(),
93             isInPrimaryState = {
94                 session?.content?.loading == false
95             },
96             secondaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_stop,
97             secondaryContentDescription = context.getString(R.string.browser_menu_stop),
98             secondaryImageTintResource = primaryTextColor(),
99             disableInSecondaryState = false,
100             longClickListener = { onItemTapped.invoke(ToolbarMenu.Item.Reload(bypassCache = true)) }
101         ) {
102             if (session?.content?.loading == true) {
103                 onItemTapped.invoke(ToolbarMenu.Item.Stop)
104             } else {
105                 onItemTapped.invoke(ToolbarMenu.Item.Reload(bypassCache = false))
106             }
107         }
109         BrowserMenuItemToolbar(listOf(back, forward, refresh))
110     }
112     private fun shouldShowOpenInApp(): Boolean = session?.let { session ->
113         val appLink = context.components.useCases.appLinksUseCases.appLinkRedirect
114         appLink(session.content.url).hasExternalApp()
115     } ?: false
117     private val menuItems by lazy {
118         val menuItems = listOf(
119             poweredBy,
120             BrowserMenuDivider(),
121             desktopMode,
122             findInPage,
123             openInApp.apply { visible = ::shouldShowOpenInApp },
124             openInFenix,
125             BrowserMenuDivider(),
126             menuToolbar
127         )
128         if (shouldReverseItems) {
129             menuItems.reversed()
130         } else {
131             menuItems
132         }
133     }
135     private val desktopMode = BrowserMenuImageSwitch(
136         imageResource = R.drawable.ic_desktop,
137         label = context.getString(R.string.browser_menu_desktop_site),
138         initialState = { session?.content?.desktopMode ?: false }
139     ) { checked ->
140         onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
141     }
143     private val findInPage = BrowserMenuImageText(
144         label = context.getString(R.string.browser_menu_find_in_page),
145         imageResource = R.drawable.mozac_ic_search,
146         iconTintColorResource = primaryTextColor()
147     ) {
148         onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
149     }
151     private val openInApp = BrowserMenuHighlightableItem(
152         label = context.getString(R.string.browser_menu_open_app_link),
153         startImageResource = R.drawable.ic_open_in_app,
154         iconTintColorResource = primaryTextColor(),
155         highlight = BrowserMenuHighlight.LowPriority(
156             label = context.getString(R.string.browser_menu_open_app_link),
157             notificationTint = getColor(context, R.color.fx_mobile_icon_color_information)
158         ),
159         isHighlighted = { !context.settings().openInAppOpened }
160     ) {
161         onItemTapped.invoke(ToolbarMenu.Item.OpenInApp)
162     }
164     private val openInFenix = SimpleBrowserMenuItem(
165         label = context.getString(R.string.browser_menu_open_in_fenix, appName),
166         textColorResource = primaryTextColor()
167     ) {
168         onItemTapped.invoke(ToolbarMenu.Item.OpenInFenix)
169     }
171     private val poweredBy = BrowserMenuCategory(
172         label = context.getStringWithArgSafe(R.string.browser_menu_powered_by, appName)
173             .uppercase(Locale.getDefault()),
174         textSize = CAPTION_TEXT_SIZE,
175         textColorResource = primaryTextColor(),
176         textStyle = Typeface.NORMAL
177     )
179     @ColorRes
180     private fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.textPrimary, context)
182     companion object {
183         private const val CAPTION_TEXT_SIZE = 12f
184     }