[fenix] 4281 remove qab (https://github.com/mozilla-mobile/fenix/pull/6310)
* For https://github.com/mozilla-mobile/fenix/issues/4281: small ToolbarMenu refactor This makes it easier to see how items are ordered in the menuItems list * For 4281: add QAB buttons to menu * For 4281: removed menu back button per mocks I double checked with UX, and we'll be relying on the hardware back button for its functionality * For 4281: add content descriptions for bookmarking * For 4281: updated BrowserToolbarController for new functionality * For 4281: provided simple dependencies to browser controller More complex changes will be in a following commit, for review readability * For 4281: move toolbar controller dependencies up to BaseBrowserFragment The functionality they control is being moved into the toolbar menu, which is shared by both normal tabs and custom ones * For 4281: removed (now unused) code related to QAB * For 4281: fix test compilation after QAB removal Tests still need to be expanded to include added functionality * For 4281: updated menu to show if url is bookmarked This sloppy workaround is required because TwoStateButton requires that `isInPrimaryState` be a synchronous call, and checking whether or not the current site is bookmarked is quite slow (10-50 MS, in my tests). After days of work and many attempted solutions, this was the least abhorrent among them. https://github.com/mozilla-mobile/android-components/issues/4915 was opened against AC to evaluate potentially supporting async `isInPrimaryState` functions. https://github.com/mozilla-mobile/fenix/issues/6370 was opened against Fenix to investigate the unexpectedly slow call to `BookmarkStorage`. * For 4281: update reader mode switch * For 4281: selectively show/hide menu items * For 4281: add reader mode appearance * For 4281: update bookmark button when it is clicked * For 4281: removed unused QAB code * For 4281: removed QAB robot, updated UI tests * For 4281: removed QuickActionSheet metrics Since this behavior now lives in the toolbar, it is tracked via Event.BrowserMenuItemTapped * For 4281: fixed lint errors * For 4281: add new strings for buttons added to menu This is necessary because the location change (from QAB to toolbar menu) could affect the grammar in some languages * For 4281: remove outdated TODOs * For 4281: removed QAB container * For 4281: removed back button reference from UI test This button no longer exists * For 4821: Fixes a visual defect (extra padding on top of toolbar) * For 4281: update copy on reader mode * For 4281: fixed review nitspull/600/head
parent
bb6977c18c
commit
2e76d82c9a
@ -1,81 +0,0 @@
|
|||||||
/* 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/. */
|
|
||||||
|
|
||||||
@file:Suppress("TooManyFunctions")
|
|
||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.test.espresso.Espresso.onView
|
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.uiautomator.UiDevice
|
|
||||||
import org.hamcrest.Matchers.allOf
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.helpers.click
|
|
||||||
import org.mozilla.fenix.helpers.isSelected
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of Robot Pattern for the quick action bar.
|
|
||||||
*/
|
|
||||||
class QuickActionBarRobot {
|
|
||||||
|
|
||||||
fun verifyAddBookmarkButton() = assertAddBookmarkButton()
|
|
||||||
|
|
||||||
fun verifyEditBookmarkButton() = assertEditBookmarkButton()
|
|
||||||
|
|
||||||
fun clickBookmarkButton() {
|
|
||||||
addBookmarkButton().click()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createBookmark(url: Uri) {
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(url) {
|
|
||||||
}.openQuickActionBar {
|
|
||||||
clickBookmarkButton()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Transition {
|
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
|
||||||
|
|
||||||
fun closeQuickActionBar(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
|
||||||
quickActionBarHandle().click()
|
|
||||||
|
|
||||||
BrowserRobot().interact()
|
|
||||||
return BrowserRobot.Transition()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun quickActionBar(interact: QuickActionBarRobot.() -> Unit): QuickActionBarRobot.Transition {
|
|
||||||
QuickActionBarRobot().interact()
|
|
||||||
return QuickActionBarRobot.Transition()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun quickActionBarHandle() = onView(withId(R.id.quick_action_sheet_handle))
|
|
||||||
|
|
||||||
private fun addBookmarkButton() =
|
|
||||||
onView(allOf(withId(R.id.quick_action_bookmark), isSelected(false)))
|
|
||||||
|
|
||||||
private fun editBookmarkButton() =
|
|
||||||
onView(allOf(withId(R.id.quick_action_bookmark), isSelected(true)))
|
|
||||||
|
|
||||||
private fun snackBarText() = onView(withId(R.id.snackbar_text))
|
|
||||||
|
|
||||||
private fun assertAddBookmarkButton() = addBookmarkButton()
|
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
|
||||||
.check(matches(withText("Bookmark")))
|
|
||||||
|
|
||||||
private fun assertBookmarkSavedSnackBarText() =
|
|
||||||
snackBarText().check(matches(withText("Bookmark saved!")))
|
|
||||||
|
|
||||||
private fun assertEditBookmarkButton() = editBookmarkButton().check(matches(withEffectiveVisibility(
|
|
||||||
ViewMatchers.Visibility.VISIBLE)))
|
|
||||||
.check(matches(withText("Edit Bookmark")))
|
|
@ -1,128 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.View
|
|
||||||
import android.view.accessibility.AccessibilityEvent
|
|
||||||
import android.view.accessibility.AccessibilityNodeInfo
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import kotlinx.android.synthetic.main.layout_quick_action_sheet.view.*
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.MainScope
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
|
|
||||||
const val POSITION_SNAP_BUFFER = 1f
|
|
||||||
|
|
||||||
class QuickActionSheet @JvmOverloads constructor(
|
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet? = null,
|
|
||||||
defStyle: Int = 0,
|
|
||||||
defStyleRes: Int = 0
|
|
||||||
) : ConstraintLayout(context, attrs, defStyle, defStyleRes) {
|
|
||||||
|
|
||||||
private val scope = MainScope()
|
|
||||||
|
|
||||||
private lateinit var quickActionSheetBehavior: QuickActionSheetBehavior<NestedScrollView>
|
|
||||||
|
|
||||||
init {
|
|
||||||
inflate(context, R.layout.layout_quick_action_sheet, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow()
|
|
||||||
quickActionSheetBehavior =
|
|
||||||
QuickActionSheetBehavior.from(quick_action_sheet.parent as NestedScrollView)
|
|
||||||
quickActionSheetBehavior.isHideable = false
|
|
||||||
setupHandle()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupHandle() {
|
|
||||||
quick_action_sheet_handle.setOnClickListener {
|
|
||||||
quickActionSheetBehavior.state = when (quickActionSheetBehavior.state) {
|
|
||||||
BottomSheetBehavior.STATE_EXPANDED -> BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
else -> BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
quick_action_sheet_handle.setAccessibilityDelegate(HandleAccessibilityDelegate(quickActionSheetBehavior))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bounceSheet() {
|
|
||||||
context.settings().incrementAutomaticBounceQuickActionSheetCount()
|
|
||||||
scope.launch(Dispatchers.Main) {
|
|
||||||
delay(BOUNCE_ANIMATION_DELAY_LENGTH)
|
|
||||||
quickActionSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
delay(BOUNCE_ANIMATION_PAUSE_LENGTH)
|
|
||||||
quickActionSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HandleAccessibilityDelegate(
|
|
||||||
private val quickActionSheetBehavior: QuickActionSheetBehavior<NestedScrollView>
|
|
||||||
) : View.AccessibilityDelegate() {
|
|
||||||
private var finalState = BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
get() = when (quickActionSheetBehavior.state) {
|
|
||||||
BottomSheetBehavior.STATE_EXPANDED,
|
|
||||||
BottomSheetBehavior.STATE_HIDDEN,
|
|
||||||
BottomSheetBehavior.STATE_COLLAPSED -> {
|
|
||||||
quickActionSheetBehavior.state
|
|
||||||
}
|
|
||||||
else -> field
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
quickActionSheetBehavior.state = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
|
|
||||||
finalState = when (action) {
|
|
||||||
AccessibilityNodeInfo.ACTION_CLICK ->
|
|
||||||
when (quickActionSheetBehavior.state) {
|
|
||||||
BottomSheetBehavior.STATE_EXPANDED -> BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
else -> BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
}
|
|
||||||
AccessibilityNodeInfo.ACTION_COLLAPSE ->
|
|
||||||
BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
AccessibilityNodeInfo.ACTION_EXPAND ->
|
|
||||||
BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
else -> return super.performAccessibilityAction(host, action, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
host?.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfo?) {
|
|
||||||
super.onInitializeAccessibilityNodeInfo(host, info)
|
|
||||||
info?.addAction(
|
|
||||||
when (finalState) {
|
|
||||||
BottomSheetBehavior.STATE_COLLAPSED,
|
|
||||||
BottomSheetBehavior.STATE_HIDDEN -> AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND
|
|
||||||
else -> AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val BOUNCE_ANIMATION_DELAY_LENGTH = 1000L
|
|
||||||
const val BOUNCE_ANIMATION_PAUSE_LENGTH = 2000L
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,68 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.session.SessionManager
|
|
||||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
import org.mozilla.fenix.ext.nav
|
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface that handles the view manipulation of the QuickActionSheet, triggered by the Interactor
|
|
||||||
*/
|
|
||||||
interface QuickActionSheetController {
|
|
||||||
fun handleShare()
|
|
||||||
fun handleDownload()
|
|
||||||
fun handleBookmark()
|
|
||||||
fun handleOpenLink()
|
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultQuickActionSheetController(
|
|
||||||
private val context: Context,
|
|
||||||
private val navController: NavController,
|
|
||||||
private val sessionManager: SessionManager,
|
|
||||||
private val appLinksUseCases: AppLinksUseCases,
|
|
||||||
private val bookmarkTapped: (Session) -> Unit
|
|
||||||
) : QuickActionSheetController {
|
|
||||||
|
|
||||||
override fun handleShare() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetShareTapped)
|
|
||||||
sessionManager.selectedSession?.url.let {
|
|
||||||
val directions = BrowserFragmentDirections.actionBrowserFragmentToShareFragment(it)
|
|
||||||
navController.nav(R.id.browserFragment, directions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleDownload() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetDownloadTapped)
|
|
||||||
ItsNotBrokenSnack(context).showSnackbar(issueNumber = "348")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleBookmark() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetBookmarkTapped)
|
|
||||||
sessionManager.selectedSession?.let {
|
|
||||||
bookmarkTapped(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleOpenLink() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetOpenInAppTapped)
|
|
||||||
|
|
||||||
val getRedirect = appLinksUseCases.appLinkRedirect
|
|
||||||
sessionManager.selectedSession?.let {
|
|
||||||
val redirect = getRedirect.invoke(it.url)
|
|
||||||
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
appLinksUseCases.openAppLink.invoke(redirect)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import org.mozilla.fenix.components.Components
|
|
||||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetAction
|
|
||||||
import java.net.MalformedURLException
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
class QuickActionSheetSessionObserver(
|
|
||||||
private val parentScope: CoroutineScope,
|
|
||||||
private val components: Components,
|
|
||||||
private val dispatch: (QuickActionSheetAction) -> Unit
|
|
||||||
) : Session.Observer {
|
|
||||||
|
|
||||||
private var findBookmarkJob: Job? = null
|
|
||||||
|
|
||||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
|
||||||
if (!loading) {
|
|
||||||
updateBookmarkState(session)
|
|
||||||
dispatch(QuickActionSheetAction.BounceNeededChange)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUrlChanged(session: Session, url: String) {
|
|
||||||
updateBookmarkState(session)
|
|
||||||
updateAppLinksState(session)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launches job to update the bookmark button on the quick action sheet.
|
|
||||||
*/
|
|
||||||
fun updateBookmarkState(session: Session) {
|
|
||||||
findBookmarkJob?.cancel()
|
|
||||||
findBookmarkJob = parentScope.launch(Main) {
|
|
||||||
val found = findBookmarkedURL(session)
|
|
||||||
dispatch(QuickActionSheetAction.BookmarkedStateChange(found))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the app link button on the quick action sheet.
|
|
||||||
*/
|
|
||||||
private fun updateAppLinksState(session: Session) {
|
|
||||||
val url = session.url
|
|
||||||
val appLinks = components.useCases.appLinksUseCases.appLinkRedirect
|
|
||||||
dispatch(QuickActionSheetAction.AppLinkStateChange(appLinks(url).hasExternalApp()))
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun findBookmarkedURL(session: Session): Boolean = withContext(IO) {
|
|
||||||
try {
|
|
||||||
val url = URL(session.url).toString()
|
|
||||||
val list = components.core.bookmarksStorage.getBookmarksWithUrl(url)
|
|
||||||
list.isNotEmpty() && list[0].url == url
|
|
||||||
} catch (e: MalformedURLException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.*
|
|
||||||
import kotlinx.android.synthetic.main.layout_quick_action_sheet.*
|
|
||||||
import kotlinx.android.synthetic.main.layout_quick_action_sheet.view.*
|
|
||||||
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserFragmentState
|
|
||||||
|
|
||||||
interface QuickActionSheetViewInteractor {
|
|
||||||
fun onQuickActionSheetOpened()
|
|
||||||
fun onQuickActionSheetClosed()
|
|
||||||
fun onQuickActionSheetSharePressed()
|
|
||||||
fun onQuickActionSheetDownloadPressed()
|
|
||||||
fun onQuickActionSheetBookmarkPressed()
|
|
||||||
fun onQuickActionSheetReadPressed()
|
|
||||||
fun onQuickActionSheetAppearancePressed()
|
|
||||||
fun onQuickActionSheetOpenLinkPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* View for the quick action sheet that slides out from the toolbar.
|
|
||||||
*/
|
|
||||||
class QuickActionSheetView(
|
|
||||||
override val containerView: ViewGroup,
|
|
||||||
private val interactor: QuickActionSheetViewInteractor
|
|
||||||
) : LayoutContainer, View.OnClickListener {
|
|
||||||
|
|
||||||
val view: NestedScrollView = LayoutInflater.from(containerView.context)
|
|
||||||
.inflate(R.layout.component_quick_action_sheet, containerView, true)
|
|
||||||
.findViewById(R.id.nestedScrollQuickAction)
|
|
||||||
|
|
||||||
private val quickActionSheet = view.quick_action_sheet as QuickActionSheet
|
|
||||||
private val quickActionSheetBehavior = QuickActionSheetBehavior.from(nestedScrollQuickAction)
|
|
||||||
|
|
||||||
init {
|
|
||||||
quickActionSheetBehavior.setQuickActionSheetCallback(object :
|
|
||||||
QuickActionSheetBehavior.QuickActionSheetCallback {
|
|
||||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
|
||||||
updateImportantForAccessibility(newState)
|
|
||||||
|
|
||||||
if (newState == QuickActionSheetBehavior.STATE_EXPANDED) {
|
|
||||||
interactor.onQuickActionSheetOpened()
|
|
||||||
} else if (newState == QuickActionSheetBehavior.STATE_COLLAPSED) {
|
|
||||||
interactor.onQuickActionSheetClosed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
|
||||||
animateOverlay(slideOffset)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
updateImportantForAccessibility(quickActionSheetBehavior.state)
|
|
||||||
|
|
||||||
quick_action_share.setOnClickListener(this)
|
|
||||||
quick_action_downloads.setOnClickListener(this)
|
|
||||||
quick_action_bookmark.setOnClickListener(this)
|
|
||||||
quick_action_read.setOnClickListener(this)
|
|
||||||
quick_action_appearance.setOnClickListener(this)
|
|
||||||
quick_action_open_app_link.setOnClickListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles clicks from quick action buttons
|
|
||||||
*/
|
|
||||||
override fun onClick(button: View) {
|
|
||||||
when (button.id) {
|
|
||||||
R.id.quick_action_share -> interactor.onQuickActionSheetSharePressed()
|
|
||||||
R.id.quick_action_downloads -> interactor.onQuickActionSheetDownloadPressed()
|
|
||||||
R.id.quick_action_bookmark -> interactor.onQuickActionSheetBookmarkPressed()
|
|
||||||
R.id.quick_action_read -> interactor.onQuickActionSheetReadPressed()
|
|
||||||
R.id.quick_action_appearance -> interactor.onQuickActionSheetAppearancePressed()
|
|
||||||
R.id.quick_action_open_app_link -> interactor.onQuickActionSheetOpenLinkPressed()
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
quickActionSheetBehavior.state = QuickActionSheetBehavior.STATE_COLLAPSED
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes alpha of overlay based on new offset of this sheet within [-1,1] range.
|
|
||||||
*/
|
|
||||||
private fun animateOverlay(offset: Float) {
|
|
||||||
quick_action_overlay.alpha = (1 - offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the important for accessibility flag on the buttons container,
|
|
||||||
* depending on if the sheet is opened or closed.
|
|
||||||
*/
|
|
||||||
private fun updateImportantForAccessibility(state: Int) {
|
|
||||||
view.quick_action_buttons_layout.importantForAccessibility = when (state) {
|
|
||||||
QuickActionSheetBehavior.STATE_COLLAPSED, QuickActionSheetBehavior.STATE_HIDDEN ->
|
|
||||||
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
|
||||||
else ->
|
|
||||||
View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(state: BrowserFragmentState) {
|
|
||||||
val quickActionSheetState = state.quickActionSheetState
|
|
||||||
view.quick_action_read.isVisible = quickActionSheetState.readable
|
|
||||||
view.quick_action_read.isSelected = quickActionSheetState.readerActive
|
|
||||||
view.quick_action_read.text = view.context.getString(
|
|
||||||
if (quickActionSheetState.readerActive) R.string.quick_action_read_close else R.string.quick_action_read
|
|
||||||
)
|
|
||||||
notifyReaderModeButton(quickActionSheetState.readable)
|
|
||||||
|
|
||||||
view.quick_action_appearance.isVisible = quickActionSheetState.readerActive
|
|
||||||
|
|
||||||
view.quick_action_bookmark.isSelected = quickActionSheetState.bookmarked
|
|
||||||
view.quick_action_bookmark.text = view.context.getString(
|
|
||||||
if (quickActionSheetState.bookmarked) {
|
|
||||||
R.string.quick_action_bookmark_edit
|
|
||||||
} else {
|
|
||||||
R.string.quick_action_bookmark
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (quickActionSheetState.bounceNeeded && view.context.settings().shouldAutoBounceQuickActionSheet) {
|
|
||||||
quickActionSheet.bounceSheet()
|
|
||||||
}
|
|
||||||
|
|
||||||
view.quick_action_open_app_link.apply {
|
|
||||||
visibility = if (quickActionSheetState.isAppLink) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun notifyReaderModeButton(readable: Boolean) {
|
|
||||||
val settings = view.context.settings().preferences
|
|
||||||
val shouldNotifyKey = view.context.getString(R.string.pref_key_reader_mode_notification)
|
|
||||||
|
|
||||||
@DrawableRes
|
|
||||||
val readerTwoStateDrawableRes = if (readable && settings.getBoolean(shouldNotifyKey, true)) {
|
|
||||||
quickActionSheet.bounceSheet()
|
|
||||||
settings.edit { putBoolean(shouldNotifyKey, false) }
|
|
||||||
R.drawable.reader_two_state_with_notification
|
|
||||||
} else {
|
|
||||||
R.drawable.reader_two_state
|
|
||||||
}
|
|
||||||
|
|
||||||
view.quick_action_read.putCompoundDrawablesRelativeWithIntrinsicBounds(
|
|
||||||
top = view.context.getDrawable(readerTwoStateDrawableRes)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/library_app_links_icon"
|
||||||
|
android:pathData="M4.5,7C3.12,7 2,5.88 2,4.5S3.12,2 4.5,2 7,3.12 7,4.5 5.88,7 4.5,7zM4.5,22C3.12,22 2,20.88 2,19.5S3.12,17 4.5,17 7,18.12 7,19.5 5.88,22 4.5,22zM4.5,14.5C3.12,14.5 2,13.38 2,12s1.12,-2.5 2.5,-2.5S7,10.62 7,12s-1.12,2.5 -2.5,2.5zM19.5,7C18.12,7 17,5.88 17,4.5S18.12,2 19.5,2 22,3.12 22,4.5 20.88,7 19.5,7zM19.5,22c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5zM19.5,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5S22,10.62 22,12s-1.12,2.5 -2.5,2.5zM12,7c-1.38,0 -2.5,-1.12 -2.5,-2.5S10.62,2 12,2s2.5,1.12 2.5,2.5S13.38,7 12,7zM12,22c-1.38,0 -2.5,-1.12 -2.5,-2.5S10.62,17 12,17s2.5,1.12 2.5,2.5S13.38,22 12,22zM12,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"
|
||||||
|
/>
|
||||||
|
</vector>
|
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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/. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M18.9,16.1c-0.5,0.4 -1,0.6 -1.5,0.8 -0.4,0.2 -0.9,0.3 -1.3,0.3 -0.6,0 -1.1,-0.2 -1.5,-0.6 -0.4,-0.4 -0.6,-0.9 -0.6,-1.6 0,-0.8 0.3,-1.3 0.9,-1.8 0.6,-0.5 1.9,-0.9 4.1,-1.3v-0.4c0,-0.6 -0.1,-1 -0.4,-1.3 -0.2,-0.3 -0.6,-0.4 -1.2,-0.4L17,9.8c-0.1,0 -0.3,0 -0.4,0.1v1.5h-1.5c-0.3,0 -0.4,0 -0.6,-0.1 -0.1,-0.1 -0.2,-0.2 -0.2,-0.5 0,-0.5 0.3,-0.9 1,-1.3s1.5,-0.6 2.5,-0.6c1.1,0 1.9,0.2 2.4,0.6 0.5,0.4 0.7,1.2 0.7,2.2L20.9,16l0.2,0.2 0.9,0.1v0.7h-2.9l-0.2,-0.9zM18.9,15.4v-2.6c-1.1,0.2 -1.8,0.5 -2.2,0.8 -0.4,0.3 -0.6,0.7 -0.6,1.1 0,0.4 0.1,0.7 0.3,0.9 0.2,0.2 0.5,0.3 0.9,0.3 0.2,0 0.4,0 0.7,-0.1 0.3,-0.1 0.6,-0.2 0.9,-0.4zM6.6,6h1.7L12,16l1,0.2v0.8L8.7,17v-0.8l1,-0.1 0.1,-0.2 -1,-2.8L5.3,13.1l-1,2.7 0.2,0.2 1,0.1v0.9L2,17v-0.8l1,-0.2L6.6,6zM7,8.2l-1.4,4h2.9L7,8.2z"
|
||||||
|
android:fillColor="@color/quick_action_reader_appearance_icon"
|
||||||
|
android:fillAlpha=".8"/>
|
||||||
|
</vector>
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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/. -->
|
|
||||||
<org.mozilla.fenix.quickactionsheet.QuickActionSheet xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/quick_action_sheet"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom" />
|
|
@ -1,141 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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/. -->
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/quick_action_sheet"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?foundation">
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/quick_action_sheet_faded_handle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?attr/neutralFaded"
|
|
||||||
android:focusable="false"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/quick_action_sheet_handle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="12dp"
|
|
||||||
android:background="@null"
|
|
||||||
android:contentDescription="@string/quick_action_sheet_handle"
|
|
||||||
android:paddingTop="7dp"
|
|
||||||
android:src="@drawable/ic_drawer_pull_tab"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/quick_action_sheet_faded_handle" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/quick_action_buttons_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:background="@null"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/quick_action_sheet_handle">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/quick_action_share"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:drawableTop="@drawable/quick_action_icon_share"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:text="@string/quick_action_share"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/quick_action_downloads"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:drawableTop="@drawable/library_icon_downloads_circle_background"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:text="@string/quick_action_download"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/quick_action_bookmark"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:drawableTop="@drawable/bookmark_two_state"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:text="@string/quick_action_bookmark"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/quick_action_appearance"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:drawableTop="@drawable/quick_action_icon_appearance"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:text="@string/quick_action_read_appearance"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/quick_action_open_app_link"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:drawableTop="@drawable/library_icon_app_links_circle_background"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:text="@string/quick_action_open_app_link"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/quick_action_read"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:drawableTop="@drawable/reader_two_state"
|
|
||||||
android:drawablePadding="5dp"
|
|
||||||
android:text="@string/quick_action_read"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/quick_action_overlay"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:alpha="0.0"
|
|
||||||
android:background="?foundation"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/quick_action_buttons_layout" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,75 +0,0 @@
|
|||||||
/* 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.toolbar
|
|
||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Assert.assertNotSame
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class BrowserFragmentStoreTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun bookmarkStateChange() = runBlocking {
|
|
||||||
val initialState = defaultBrowserState()
|
|
||||||
val store = BrowserFragmentStore(initialState)
|
|
||||||
|
|
||||||
store.dispatch(QuickActionSheetAction.BookmarkedStateChange(true)).join()
|
|
||||||
assertNotSame(initialState, store.state)
|
|
||||||
assertEquals(store.state.quickActionSheetState.bookmarked, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun readableStateChange() = runBlocking {
|
|
||||||
val initialState = defaultBrowserState()
|
|
||||||
val store = BrowserFragmentStore(initialState)
|
|
||||||
|
|
||||||
store.dispatch(QuickActionSheetAction.ReadableStateChange(true)).join()
|
|
||||||
assertNotSame(initialState, store.state)
|
|
||||||
assertEquals(store.state.quickActionSheetState.readable, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun readerActiveStateChange() = runBlocking {
|
|
||||||
val initialState = defaultBrowserState()
|
|
||||||
val store = BrowserFragmentStore(initialState)
|
|
||||||
|
|
||||||
store.dispatch(QuickActionSheetAction.ReaderActiveStateChange(true)).join()
|
|
||||||
assertNotSame(initialState, store.state)
|
|
||||||
assertEquals(store.state.quickActionSheetState.readerActive, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun bounceNeededChange() = runBlocking {
|
|
||||||
val initialState = defaultBrowserState()
|
|
||||||
val store = BrowserFragmentStore(initialState)
|
|
||||||
|
|
||||||
store.dispatch(QuickActionSheetAction.BounceNeededChange).join()
|
|
||||||
assertNotSame(initialState, store.state)
|
|
||||||
assertEquals(store.state.quickActionSheetState.bounceNeeded, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun appLinkStateChange() = runBlocking {
|
|
||||||
val initialState = defaultBrowserState()
|
|
||||||
val store = BrowserFragmentStore(initialState)
|
|
||||||
|
|
||||||
store.dispatch(QuickActionSheetAction.AppLinkStateChange(true)).join()
|
|
||||||
assertNotSame(initialState, store.state)
|
|
||||||
assertEquals(store.state.quickActionSheetState.isAppLink, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun defaultBrowserState(): BrowserFragmentState = BrowserFragmentState(
|
|
||||||
quickActionSheetState = defaultQuickActionSheetState()
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun defaultQuickActionSheetState(): QuickActionSheetState = QuickActionSheetState(
|
|
||||||
readable = false,
|
|
||||||
bookmarked = false,
|
|
||||||
readerActive = false,
|
|
||||||
bounceNeeded = false,
|
|
||||||
isAppLink = false
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.quickactionsheet
|
|
||||||
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.verify
|
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.session.SessionManager
|
|
||||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.mozilla.fenix.HomeActivity
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
import org.mozilla.fenix.ext.nav
|
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
|
||||||
|
|
||||||
class DefaultQuickActionSheetControllerTest {
|
|
||||||
private val context: HomeActivity = mockk(relaxed = true)
|
|
||||||
private val navController: NavController = mockk(relaxed = true)
|
|
||||||
private val sessionManager: SessionManager = mockk(relaxed = true)
|
|
||||||
private val currentSession: Session = mockk(relaxed = true)
|
|
||||||
private val appLinksUseCases: AppLinksUseCases = mockk(relaxed = true)
|
|
||||||
private val bookmarkTapped: (Session) -> Unit = mockk(relaxed = true)
|
|
||||||
private val metrics: MetricController = mockk(relaxed = true)
|
|
||||||
|
|
||||||
private lateinit var controller: DefaultQuickActionSheetController
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
controller = DefaultQuickActionSheetController(
|
|
||||||
context,
|
|
||||||
navController,
|
|
||||||
sessionManager,
|
|
||||||
appLinksUseCases,
|
|
||||||
bookmarkTapped
|
|
||||||
)
|
|
||||||
|
|
||||||
every { sessionManager.selectedSession } returns currentSession
|
|
||||||
|
|
||||||
every { context.metrics } returns metrics
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleShare() {
|
|
||||||
controller.handleShare()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetShareTapped) }
|
|
||||||
verify {
|
|
||||||
navController.nav(
|
|
||||||
R.id.browserFragment,
|
|
||||||
BrowserFragmentDirections.actionBrowserFragmentToShareFragment(currentSession.url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleDownload() {
|
|
||||||
controller.handleDownload()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetDownloadTapped) }
|
|
||||||
verify { ItsNotBrokenSnack(context).showSnackbar(issueNumber = "348") }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleBookmark() {
|
|
||||||
controller.handleBookmark()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetBookmarkTapped) }
|
|
||||||
verify { bookmarkTapped(currentSession) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleOpenLink() {
|
|
||||||
controller.handleOpenLink()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetOpenInAppTapped) }
|
|
||||||
verify { appLinksUseCases.appLinkRedirect.invoke(currentSession.url) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/* 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.quickactionsheet
|
|
||||||
|
|
||||||
import io.mockk.Runs
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.just
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.spyk
|
|
||||||
import io.mockk.verify
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.feature.app.links.AppLinkRedirect
|
|
||||||
import mozilla.components.feature.app.links.AppLinksUseCases
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.mozilla.fenix.components.Components
|
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserFragmentStore
|
|
||||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetAction
|
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
|
||||||
class QuickActionSheetSessionObserverTest {
|
|
||||||
|
|
||||||
private lateinit var components: Components
|
|
||||||
private lateinit var appLinkRedirect: AppLinksUseCases.GetAppLinkRedirect
|
|
||||||
private lateinit var store: BrowserFragmentStore
|
|
||||||
private lateinit var dispatch: (QuickActionSheetAction) -> Unit
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
components = mockk(relaxed = true)
|
|
||||||
appLinkRedirect = mockk(relaxed = true)
|
|
||||||
store = mockk(relaxed = true)
|
|
||||||
dispatch = { store.dispatch(it) }
|
|
||||||
|
|
||||||
every { components.useCases.appLinksUseCases.appLinkRedirect } returns appLinkRedirect
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `onLoadingStateChanged dispatches BounceNeededChange and updates bookmark button`() {
|
|
||||||
val session: Session = mockk()
|
|
||||||
val observer = spyk(QuickActionSheetSessionObserver(mockk(), components, dispatch))
|
|
||||||
every { observer.updateBookmarkState(session) } just Runs
|
|
||||||
|
|
||||||
observer.onLoadingStateChanged(session, true)
|
|
||||||
verify(exactly = 0) { store.dispatch(QuickActionSheetAction.BounceNeededChange) }
|
|
||||||
|
|
||||||
observer.onLoadingStateChanged(session, false)
|
|
||||||
verify { observer.updateBookmarkState(session) }
|
|
||||||
verify { store.dispatch(QuickActionSheetAction.BounceNeededChange) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `onUrlChanged updates bookmark and app link buttons`() {
|
|
||||||
val url = "https://example.com"
|
|
||||||
val session: Session = mockk()
|
|
||||||
every { session.url } returns url
|
|
||||||
|
|
||||||
val observer = spyk(QuickActionSheetSessionObserver(mockk(), components, dispatch))
|
|
||||||
every { observer.updateBookmarkState(session) } just Runs
|
|
||||||
every { appLinkRedirect.invoke(url) } returns AppLinkRedirect(mockk(), "", false)
|
|
||||||
|
|
||||||
observer.onUrlChanged(session, "")
|
|
||||||
verify { observer.updateBookmarkState(session) }
|
|
||||||
verify { appLinkRedirect.invoke("https://example.com") }
|
|
||||||
verify { store.dispatch(QuickActionSheetAction.AppLinkStateChange(true)) }
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue