Bug 1885602 - Part 4: Implement navigating to the settings from the menu header for...
[gecko.git] / mobile / android / fenix / app / src / main / java / org / mozilla / fenix / components / FindInPageIntegration.kt
blob25de562cd561fa20bb7d1e0ae30c68632fc7bec4
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
23 /**
24  * BrowserFragment delegate to handle all layout updates needed to show or hide the find in page bar.
25  *
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.
33  */
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() {
45         feature.start()
46     }
48     override fun stop() {
49         feature.stop()
50     }
52     override fun onBackPressed(): Boolean {
53         return feature.onBackPressed()
54     }
56     private fun onClose() {
57         view.visibility = View.GONE
58         restorePreviousLayout()
59     }
61     /**
62      * Start the find in page functionality.
63      */
64     @UiThread
65     fun launch() {
66         onLaunch(view, feature)
67     }
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
76         }
77     }
79     @VisibleForTesting
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
89             } else {
90                 engineViewParent.translationY = 0f
91             }
92         } else {
93             if (toolbarInfo.isToolbarDynamic) {
94                 engineViewParentParams.bottomMargin = 0
95             }
96         }
97     }
99     @VisibleForTesting
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)
111             } else {
112                 // With a fixed toolbar the EngineView is anchored below the toolbar with 0 Y translation.
113                 engineViewParent.translationY = -toolbarInfo.toolbar.height.toFloat()
114             }
115         } else {
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
119         }
120     }
122     @VisibleForTesting
123     internal fun getEngineViewParent() = engineView.asView().parent as View
125     @VisibleForTesting
126     internal fun getEngineViewsParentLayoutParams() = getEngineViewParent().layoutParams as MarginLayoutParams
128     /**
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.
131      */
132     data class ToolbarInfo(
133         val toolbar: View,
134         val isToolbarDynamic: Boolean,
135         val isToolbarPlacedAtTop: Boolean,
136     )