[fenix] For https://github.com/mozilla-mobile/fenix/issues/19876 - Part 1: Refactor...
[gecko.git] / mobile / android / fenix / app / src / main / java / org / mozilla / fenix / components / toolbar / ToolbarIntegration.kt
blobd778e7abe1f67de959c95111b2f58a3a2f69f00a
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.components.toolbar
7 import android.content.Context
8 import android.content.res.Configuration
9 import androidx.appcompat.content.res.AppCompatResources
10 import androidx.core.content.ContextCompat
11 import androidx.lifecycle.LifecycleOwner
12 import kotlinx.coroutines.ExperimentalCoroutinesApi
13 import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
14 import mozilla.components.browser.state.selector.normalTabs
15 import mozilla.components.browser.state.selector.privateTabs
16 import mozilla.components.browser.toolbar.BrowserToolbar
17 import mozilla.components.browser.toolbar.display.DisplayToolbar
18 import mozilla.components.concept.engine.Engine
19 import mozilla.components.concept.storage.HistoryStorage
20 import mozilla.components.feature.tabs.toolbar.TabCounterToolbarButton
21 import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
22 import mozilla.components.feature.toolbar.ToolbarBehaviorController
23 import mozilla.components.feature.toolbar.ToolbarFeature
24 import mozilla.components.feature.toolbar.ToolbarPresenter
25 import mozilla.components.support.base.feature.LifecycleAwareFeature
26 import mozilla.components.support.ktx.android.view.hideKeyboard
27 import org.mozilla.fenix.R
28 import org.mozilla.fenix.components.toolbar.interactor.BrowserToolbarInteractor
29 import org.mozilla.fenix.ext.components
30 import org.mozilla.fenix.ext.settings
31 import org.mozilla.fenix.theme.ThemeManager
33 @ExperimentalCoroutinesApi
34 abstract class ToolbarIntegration(
35     context: Context,
36     toolbar: BrowserToolbar,
37     toolbarMenu: ToolbarMenu,
38     sessionId: String?,
39     isPrivate: Boolean,
40     renderStyle: ToolbarFeature.RenderStyle
41 ) : LifecycleAwareFeature {
43     val store = context.components.core.store
44     private val toolbarPresenter: ToolbarPresenter = ToolbarPresenter(
45         toolbar,
46         store,
47         sessionId,
48         ToolbarFeature.UrlRenderConfiguration(
49             context.components.publicSuffixList,
50             ThemeManager.resolveAttribute(R.attr.primaryText, context),
51             renderStyle = renderStyle
52         )
53     )
55     private val menuPresenter =
56         MenuPresenter(toolbar, context.components.core.store, sessionId)
58     private val toolbarController = ToolbarBehaviorController(toolbar, store, sessionId)
60     init {
61         toolbar.display.menuBuilder = toolbarMenu.menuBuilder
62         toolbar.private = isPrivate
63     }
65     override fun start() {
66         menuPresenter.start()
67         toolbarPresenter.start()
68         toolbarController.start()
69     }
71     override fun stop() {
72         menuPresenter.stop()
73         toolbarPresenter.stop()
74         toolbarController.stop()
75     }
77     fun invalidateMenu() {
78         menuPresenter.invalidateActions()
79     }
82 @ExperimentalCoroutinesApi
83 class DefaultToolbarIntegration(
84     context: Context,
85     toolbar: BrowserToolbar,
86     toolbarMenu: ToolbarMenu,
87     domainAutocompleteProvider: DomainAutocompleteProvider,
88     historyStorage: HistoryStorage,
89     lifecycleOwner: LifecycleOwner,
90     sessionId: String? = null,
91     isPrivate: Boolean,
92     interactor: BrowserToolbarInteractor,
93     engine: Engine
94 ) : ToolbarIntegration(
95     context = context,
96     toolbar = toolbar,
97     toolbarMenu = toolbarMenu,
98     sessionId = sessionId,
99     isPrivate = isPrivate,
100     renderStyle = ToolbarFeature.RenderStyle.UncoloredUrl
101 ) {
103     init {
104         toolbar.display.menuBuilder = toolbarMenu.menuBuilder
105         toolbar.private = isPrivate
107         val drawable =
108             if (isPrivate) AppCompatResources.getDrawable(
109                 context,
110                 R.drawable.shield_dark
111             ) else when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
112                 Configuration.UI_MODE_NIGHT_UNDEFINED, // We assume light here per Android doc's recommendation
113                 Configuration.UI_MODE_NIGHT_NO -> {
114                     AppCompatResources.getDrawable(context, R.drawable.shield_light)
115                 }
116                 Configuration.UI_MODE_NIGHT_YES -> {
117                     AppCompatResources.getDrawable(context, R.drawable.shield_dark)
118                 }
119                 else -> AppCompatResources.getDrawable(context, R.drawable.shield_light)
120             }
122         toolbar.display.indicators =
123             if (context.settings().shouldUseTrackingProtection) {
124                 listOf(
125                     DisplayToolbar.Indicators.TRACKING_PROTECTION,
126                     DisplayToolbar.Indicators.SECURITY,
127                     DisplayToolbar.Indicators.EMPTY,
128                     DisplayToolbar.Indicators.HIGHLIGHT
129                 )
130             } else {
131                 listOf(
132                     DisplayToolbar.Indicators.SECURITY,
133                     DisplayToolbar.Indicators.EMPTY,
134                     DisplayToolbar.Indicators.HIGHLIGHT
135                 )
136             }
137             context.settings().shouldUseTrackingProtection
139         toolbar.display.icons = toolbar.display.icons.copy(
140             emptyIcon = null,
141             trackingProtectionTrackersBlocked = drawable!!,
142             trackingProtectionNothingBlocked = AppCompatResources.getDrawable(
143                 context,
144                 R.drawable.ic_tracking_protection_enabled
145             )!!,
146             trackingProtectionException = AppCompatResources.getDrawable(
147                 context,
148                 R.drawable.ic_tracking_protection_disabled
149             )!!
150         )
152         val tabCounterMenu = FenixTabCounterMenu(
153             context = context,
154             onItemTapped = {
155                 interactor.onTabCounterMenuItemTapped(it)
156             },
157             iconColor =
158                 if (isPrivate) {
159                     ContextCompat.getColor(context, R.color.primary_text_private_theme)
160                 } else {
161                     null
162                 }
163         ).also {
164             it.updateMenu(context.settings().toolbarPosition)
165         }
167         val tabsAction = TabCounterToolbarButton(
168             lifecycleOwner = lifecycleOwner,
169             showTabs = {
170                 toolbar.hideKeyboard()
171                 interactor.onTabCounterClicked()
172             },
173             store = store,
174             menu = tabCounterMenu
175         )
177         val tabCount = if (isPrivate) {
178             store.state.privateTabs.size
179         } else {
180             store.state.normalTabs.size
181         }
183         tabsAction.updateCount(tabCount)
185         toolbar.addBrowserAction(tabsAction)
187         val engineForSpeculativeConnects = if (!isPrivate) engine else null
188         ToolbarAutocompleteFeature(
189             toolbar,
190             engineForSpeculativeConnects
191         ).apply {
192             addDomainProvider(domainAutocompleteProvider)
193             if (context.settings().shouldShowHistorySuggestions) {
194                 addHistoryStorageProvider(historyStorage)
195             }
196         }
197     }