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
7 import android.view.View
8 import android.view.ViewGroup.MarginLayoutParams
9 import androidx.annotation.UiThread
10 import androidx.annotation.VisibleForTesting
11 import androidx.core.view.isVisible
12 import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab
13 import mozilla.components.browser.state.store.BrowserStore
14 import mozilla.components.browser.toolbar.BrowserToolbar
15 import mozilla.components.concept.engine.EngineView
16 import mozilla.components.feature.findinpage.FindInPageFeature
17 import mozilla.components.feature.findinpage.view.FindInPageBar
18 import mozilla.components.support.base.feature.LifecycleAwareFeature
19 import mozilla.components.support.base.feature.UserInteractionHandler
20 import org.mozilla.fenix.R
21 import org.mozilla.fenix.components.FindInPageIntegration.ToolbarInfo
24 * BrowserFragment delegate to handle all layout updates needed to show or hide the find in page bar.
26 * @param store The [BrowserStore] used to look up the current selected tab.
27 * @param sessionId ID of the [store] session in which the query will be performed.
28 * @param view The [FindInPageBar] view to display.
29 * @param engineView the browser in which the queries will be made and which needs to be better positioned
30 * to suit the find in page bar.
31 * @param toolbarInfo [ToolbarInfo] used to configure the [BrowserToolbar] while the find in page bar is shown.
32 * @param findInPageHeight The height of the find in page bar.
34 class FindInPageIntegration(
35 private val store: BrowserStore,
36 private val sessionId: String? = null,
37 private val view: FindInPageBar,
38 private val engineView: EngineView,
39 private val toolbarInfo: ToolbarInfo,
40 private val findInPageHeight: Int = view.context.resources.getDimensionPixelSize(R.dimen.browser_toolbar_height),
41 ) : LifecycleAwareFeature, UserInteractionHandler {
42 private val feature by lazy { FindInPageFeature(store, view, engineView, ::onClose) }
44 override fun start() {
52 override fun onBackPressed(): Boolean {
53 return feature.onBackPressed()
56 private fun onClose() {
57 view.visibility = View.GONE
58 restorePreviousLayout()
62 * Start the find in page functionality.
66 onLaunch(view, feature)
69 private fun onLaunch(view: View, feature: LifecycleAwareFeature) {
70 store.state.findCustomTabOrSelectedTab(sessionId)?.let { tab ->
71 prepareLayoutForFindBar()
73 view.visibility = View.VISIBLE
74 (feature as FindInPageFeature).bind(tab)
75 view.layoutParams.height = findInPageHeight
80 internal fun restorePreviousLayout() {
81 toolbarInfo.toolbar.isVisible = true
83 val engineViewParent = getEngineViewParent()
84 val engineViewParentParams = getEngineViewsParentLayoutParams()
85 if (toolbarInfo.isToolbarPlacedAtTop) {
86 if (toolbarInfo.isToolbarDynamic) {
87 engineViewParent.translationY = toolbarInfo.toolbar.height.toFloat()
88 engineViewParentParams.bottomMargin = 0
90 engineViewParent.translationY = 0f
93 if (toolbarInfo.isToolbarDynamic) {
94 engineViewParentParams.bottomMargin = 0
100 internal fun prepareLayoutForFindBar() {
101 toolbarInfo.toolbar.isVisible = false
103 val engineViewParent = getEngineViewParent()
104 val engineViewParentParams = getEngineViewsParentLayoutParams()
105 if (toolbarInfo.isToolbarPlacedAtTop) {
106 if (toolbarInfo.isToolbarDynamic) {
107 // With a dynamic toolbar the EngineView extends to the entire (top and bottom) of the screen.
108 // And now with the toolbar expanded it is translated down immediately below the toolbar.
109 engineViewParent.translationY = 0f
110 engineViewParentParams.bottomMargin = minOf(toolbarInfo.toolbar.height, findInPageHeight)
112 // With a fixed toolbar the EngineView is anchored below the toolbar with 0 Y translation.
113 engineViewParent.translationY = -toolbarInfo.toolbar.height.toFloat()
116 // With a bottom toolbar the EngineView is already anchored to the top of the screen.
117 // Need just to ensure space for the find in page bar under the engineView.
118 engineViewParentParams.bottomMargin = toolbarInfo.toolbar.height
123 internal fun getEngineViewParent() = engineView.asView().parent as View
126 internal fun getEngineViewsParentLayoutParams() = getEngineViewParent().layoutParams as MarginLayoutParams
129 * Holder of all details needed about the Toolbar.
130 * Used to modify the layout of BrowserToolbar while the find in page bar is shown.
132 data class ToolbarInfo(
134 val isToolbarDynamic: Boolean,
135 val isToolbarPlacedAtTop: Boolean,