diff --git a/app/build.gradle b/app/build.gradle index aac8dc78a..de6df0948 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -124,10 +124,9 @@ dependencies { implementation Deps.mozilla_feature_session implementation Deps.mozilla_feature_toolbar implementation Deps.mozilla_feature_tabs - implementation Deps.mozilla_service_fretboard implementation Deps.mozilla_service_glean - + implementation Deps.mozilla_feature_findinpage implementation Deps.mozilla_support_ktx implementation Deps.mozilla_lib_crash diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 59ddaeaba..7200b00bd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,8 @@ android:theme="@style/LightAppTheme" android:usesCleartextTraffic="true" tools:ignore="UnusedAttribute"> - + @@ -53,4 +54,4 @@ android:theme="@style/SettingsAppTheme" /> - \ No newline at end of file + diff --git a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt index ed6258afa..863c3a900 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -28,11 +28,13 @@ import org.mozilla.fenix.components.toolbar.ToolbarIntegration import org.mozilla.fenix.ext.requireComponents import mozilla.components.feature.prompts.PromptFeature import org.mozilla.fenix.BackHandler +import org.mozilla.fenix.components.FindInPageIntegration class BrowserFragment : Fragment(), BackHandler { private lateinit var contextMenuFeature: ContextMenuFeature private lateinit var downloadsFeature: DownloadsFeature + private lateinit var findInPageIntegration: FindInPageIntegration private lateinit var promptsFeature: PromptFeature private lateinit var sessionFeature: SessionFeature @@ -88,6 +90,14 @@ class BrowserFragment : Fragment(), BackHandler { engineView ) + findInPageIntegration = FindInPageIntegration(requireComponents.core.sessionManager, findInPageView) + val toolbarIntegration = ToolbarIntegration( + requireContext(), + toolbar, + requireComponents.toolbar.shippedDomainsProvider, + requireComponents.core.historyStorage + ) + // Stop toolbar from collapsing if TalkBack is enabled val accessibilityManager = context?.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager if (accessibilityManager.isEnabled) { @@ -98,12 +108,10 @@ class BrowserFragment : Fragment(), BackHandler { lifecycle.addObservers( contextMenuFeature, downloadsFeature, + findInPageIntegration, promptsFeature, sessionFeature, - ToolbarIntegration(requireContext(), - toolbar, - requireComponents.toolbar.shippedDomainsProvider, - requireComponents.core.historyStorage) + toolbarIntegration ) toolbar.onUrlClicked = { @@ -113,6 +121,7 @@ class BrowserFragment : Fragment(), BackHandler { } override fun onBackPressed(): Boolean { + if (findInPageIntegration.onBackPressed()) return true if (sessionFeature.handleBackPressed()) return true // We'll want to improve this when we add multitasking diff --git a/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt b/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt new file mode 100644 index 000000000..f12c7de95 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt @@ -0,0 +1,94 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.components + +import android.content.Context +import android.util.AttributeSet +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent +import android.view.View +import androidx.coordinatorlayout.widget.CoordinatorLayout +import mozilla.components.browser.session.SessionManager +import mozilla.components.browser.toolbar.BrowserToolbar +import mozilla.components.feature.findinpage.FindInPageFeature +import mozilla.components.feature.findinpage.view.FindInPageBar +import mozilla.components.feature.findinpage.view.FindInPageView + +class FindInPageIntegration( + private val sessionManager: SessionManager, + private val view: FindInPageView +) : LifecycleObserver { + private val feature = FindInPageFeature(sessionManager, view, ::onClose) + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + fun onStart() { + feature.start() + + FindInPageIntegration.launch = this::launch + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + fun onStop() { + feature.stop() + + FindInPageIntegration.launch = null + } + + fun onBackPressed(): Boolean { + return feature.onBackPressed() + } + + private fun onClose() { + view.asView().visibility = View.GONE + } + + private fun launch() { + val session = sessionManager.selectedSession ?: return + + view.asView().visibility = View.VISIBLE + feature.bind(session) + } + + companion object { + // This is a workaround to let the menu item find this integration and active "Find in Page" mode. That's a bit + // ridiculous and there's no need that we create the toolbar menu items at app start time. Instead the + // ToolbarIntegration should create them and get the FindInPageIntegration injected as a dependency if the + // menu items need them. + var launch: (() -> Unit)? = null + private set + } +} + +/** + * [CoordinatorLayout.Behavior] that will always position the [FindInPageBar] above the [BrowserToolbar] (including + * when the browser toolbar is scrolling or performing a snap animation). + */ +@Suppress("unused") // Referenced from XML +class FindInPageBarBehavior( + context: Context, + attrs: AttributeSet +) : CoordinatorLayout.Behavior(context, attrs) { + override fun layoutDependsOn(parent: CoordinatorLayout, child: FindInPageBar, dependency: View): Boolean { + if (dependency is BrowserToolbar) { + return true + } + + return super.layoutDependsOn(parent, child, dependency) + } + + override fun onDependentViewChanged(parent: CoordinatorLayout, child: FindInPageBar, dependency: View): Boolean { + return if (dependency is BrowserToolbar) { + repositionFindInPageBar(child, dependency) + true + } else { + false + } + } + + private fun repositionFindInPageBar(findInPageView: FindInPageBar, toolbar: BrowserToolbar) { + findInPageView.translationY = (toolbar.translationY + toolbar.height * -1.0).toFloat() + } +} diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/Toolbar.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/Toolbar.kt index cadada2bd..add4d1181 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/Toolbar.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/Toolbar.kt @@ -17,6 +17,7 @@ import mozilla.components.feature.session.SessionUseCases import org.mozilla.fenix.R import org.mozilla.fenix.ext.share import org.mozilla.fenix.settings.SettingsActivity +import org.mozilla.fenix.components.FindInPageIntegration /** * Component group for all functionality related to the browser toolbar. @@ -112,7 +113,9 @@ class Toolbar( context.getString(R.string.browser_menu_find_in_page), R.color.icons ) { - // TODO Find in Page + FindInPageIntegration.launch?.invoke() + }.apply { + visible = { sessionManager.selectedSession != null } }, BrowserMenuImageText( diff --git a/app/src/main/res/layout/fragment_browser.xml b/app/src/main/res/layout/fragment_browser.xml index 98d037eea..b7abf67da 100644 --- a/app/src/main/res/layout/fragment_browser.xml +++ b/app/src/main/res/layout/fragment_browser.xml @@ -31,6 +31,17 @@ mozac:awesomeBarTitleTextColor="#ffffff" /> + + + \ No newline at end of file diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 5266f5772..3072728d1 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -72,6 +72,7 @@ object Deps { const val mozilla_feature_storage = "org.mozilla.components:feature-storage:${Versions.mozilla_android_components}" const val mozilla_feature_prompts = "org.mozilla.components:feature-prompts:${Versions.mozilla_android_components}" const val mozilla_feature_toolbar = "org.mozilla.components:feature-toolbar:${Versions.mozilla_android_components}" + const val mozilla_feature_findinpage = "org.mozilla.components:feature-findinpage:${Versions.mozilla_android_components}" const val mozilla_service_fretboard = "org.mozilla.components:service-fretboard:${Versions.mozilla_android_components}" const val mozilla_service_glean = "org.mozilla.components:service-glean:${Versions.mozilla_android_components}"