mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-03 23:15:31 +00:00
[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 nits
This commit is contained in:
parent
bb6977c18c
commit
2e76d82c9a
@ -276,74 +276,6 @@ find_in_page:
|
|||||||
- fenix-core@mozilla.com
|
- fenix-core@mozilla.com
|
||||||
expires: "2020-03-01"
|
expires: "2020-03-01"
|
||||||
|
|
||||||
quick_action_sheet:
|
|
||||||
opened:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
A user opened the quick action sheet UI
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issue/1195
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-03-01"
|
|
||||||
closed:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
A user closed the quick action sheet UI
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issue/1195
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-03-01"
|
|
||||||
share_tapped:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
A user tapped the share button
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issue/1195
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-03-01"
|
|
||||||
bookmark_tapped:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
A user tapped the bookmark button
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issue/1195
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-03-01"
|
|
||||||
download_tapped:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
A user tapped the download button
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issue/1195
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-03-01"
|
|
||||||
open_app_tapped:
|
|
||||||
type: event
|
|
||||||
description: >
|
|
||||||
A user tapped the open in app button
|
|
||||||
bugs:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/issue/1195
|
|
||||||
data_reviews:
|
|
||||||
- https://github.com/mozilla-mobile/fenix/pull/4629
|
|
||||||
notification_emails:
|
|
||||||
- fenix-core@mozilla.com
|
|
||||||
expires: "2020-03-01"
|
|
||||||
|
|
||||||
metrics:
|
metrics:
|
||||||
default_browser:
|
default_browser:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
@ -18,7 +18,6 @@ import org.mozilla.fenix.helpers.TestAssetHelper
|
|||||||
import org.mozilla.fenix.ui.robots.browserScreen
|
import org.mozilla.fenix.ui.robots.browserScreen
|
||||||
import org.mozilla.fenix.ui.robots.homeScreen
|
import org.mozilla.fenix.ui.robots.homeScreen
|
||||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
import org.mozilla.fenix.ui.robots.quickActionBar
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for verifying basic functionality of bookmarks
|
* Tests for verifying basic functionality of bookmarks
|
||||||
@ -66,12 +65,12 @@ class BookmarksTest {
|
|||||||
|
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
}.openQuickActionBar {
|
}.openThreeDotMenu {
|
||||||
verifyAddBookmarkButton()
|
verifyAddBookmarkButton()
|
||||||
clickBookmarkButton()
|
clickAddBookmarkButton()
|
||||||
}
|
}
|
||||||
browserScreen {
|
browserScreen {
|
||||||
}.openQuickActionBar {
|
}.openThreeDotMenu {
|
||||||
verifyEditBookmarkButton()
|
verifyEditBookmarkButton()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,11 +79,8 @@ class BookmarksTest {
|
|||||||
fun addBookmarkTest() {
|
fun addBookmarkTest() {
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
quickActionBar {
|
browserScreen {
|
||||||
createBookmark(defaultWebPage.url)
|
createBookmark(defaultWebPage.url)
|
||||||
}
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openLibrary {
|
}.openLibrary {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
@ -109,9 +105,8 @@ class BookmarksTest {
|
|||||||
fun editBookmarkViewTest() {
|
fun editBookmarkViewTest() {
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
quickActionBar { createBookmark(defaultWebPage.url) }
|
browserScreen {
|
||||||
|
createBookmark(defaultWebPage.url)
|
||||||
navigationToolbar {
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openLibrary {
|
}.openLibrary {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
@ -130,9 +125,8 @@ class BookmarksTest {
|
|||||||
fun copyBookmarkURLTest() {
|
fun copyBookmarkURLTest() {
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
quickActionBar { createBookmark(defaultWebPage.url) }
|
browserScreen {
|
||||||
|
createBookmark(defaultWebPage.url)
|
||||||
navigationToolbar {
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openLibrary {
|
}.openLibrary {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
@ -146,9 +140,8 @@ class BookmarksTest {
|
|||||||
fun openBookmarkInNewTabTest() {
|
fun openBookmarkInNewTabTest() {
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
quickActionBar { createBookmark(defaultWebPage.url) }
|
browserScreen {
|
||||||
|
createBookmark(defaultWebPage.url)
|
||||||
navigationToolbar {
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openLibrary {
|
}.openLibrary {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
@ -164,9 +157,8 @@ class BookmarksTest {
|
|||||||
fun openBookmarkInPrivateTabTest() {
|
fun openBookmarkInPrivateTabTest() {
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
quickActionBar { createBookmark(defaultWebPage.url) }
|
browserScreen {
|
||||||
|
createBookmark(defaultWebPage.url)
|
||||||
navigationToolbar {
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openLibrary {
|
}.openLibrary {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
@ -182,9 +174,8 @@ class BookmarksTest {
|
|||||||
fun deleteBookmarkTest() {
|
fun deleteBookmarkTest() {
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
quickActionBar { createBookmark(defaultWebPage.url) }
|
browserScreen {
|
||||||
|
createBookmark(defaultWebPage.url)
|
||||||
navigationToolbar {
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openLibrary {
|
}.openLibrary {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
|
@ -65,7 +65,6 @@ class NavigationToolbarTest {
|
|||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
verifyThreeDotMenuExists()
|
verifyThreeDotMenuExists()
|
||||||
verifyBackButton()
|
|
||||||
}.goBack {
|
}.goBack {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package org.mozilla.fenix.ui.robots
|
package org.mozilla.fenix.ui.robots
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
@ -67,6 +68,14 @@ class BrowserRobot {
|
|||||||
TestAssetHelper.waitingTime)
|
TestAssetHelper.waitingTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createBookmark(url: Uri) {
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(url) {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
clickAddBookmarkButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Transition {
|
class Transition {
|
||||||
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
private fun threeDotButton() = onView(
|
private fun threeDotButton() = onView(
|
||||||
@ -106,16 +115,6 @@ class BrowserRobot {
|
|||||||
HomeScreenRobot().interact()
|
HomeScreenRobot().interact()
|
||||||
return HomeScreenRobot.Transition()
|
return HomeScreenRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openQuickActionBar(interact: QuickActionBarRobot.() -> Unit): QuickActionBarRobot.Transition {
|
|
||||||
mDevice.waitNotNull(Until.gone(By.res("org.mozilla.fenix.debug:id/quick_action_sheet")),
|
|
||||||
TestAssetHelper.waitingTime
|
|
||||||
)
|
|
||||||
quickActionBarHandle().click()
|
|
||||||
|
|
||||||
QuickActionBarRobot().interact()
|
|
||||||
return QuickActionBarRobot.Transition()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,4 +132,3 @@ fun dismissTrackingOnboarding() {
|
|||||||
fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
|
fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))
|
||||||
|
|
||||||
private fun tabsCounter() = onView(withId(R.id.counter_box))
|
private fun tabsCounter() = onView(withId(R.id.counter_box))
|
||||||
private fun quickActionBarHandle() = onView(withId(R.id.quick_action_sheet_handle))
|
|
||||||
|
@ -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")))
|
|
@ -11,11 +11,11 @@ import androidx.test.espresso.action.ViewActions
|
|||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.hasFocus
|
import androidx.test.espresso.matcher.ViewMatchers.hasFocus
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
@ -38,7 +38,8 @@ class ThreeDotMenuMainRobot {
|
|||||||
fun verifyHelpButton() = assertHelpButton()
|
fun verifyHelpButton() = assertHelpButton()
|
||||||
fun verifyThreeDotMenuExists() = threeDotMenuRecyclerViewExists()
|
fun verifyThreeDotMenuExists() = threeDotMenuRecyclerViewExists()
|
||||||
fun verifyForwardButton() = assertForwardButton()
|
fun verifyForwardButton() = assertForwardButton()
|
||||||
fun verifyBackButton() = assertBackButton()
|
fun verifyAddBookmarkButton() = assertAddBookmarkButton()
|
||||||
|
fun verifyEditBookmarkButton() = assertEditBookmarkButton()
|
||||||
fun verifyRefreshButton() = assertRefreshButton()
|
fun verifyRefreshButton() = assertRefreshButton()
|
||||||
fun verifyCloseAllTabsButton() = assertCloseAllTabsButton()
|
fun verifyCloseAllTabsButton() = assertCloseAllTabsButton()
|
||||||
fun verifyShareButton() = assertShareButton()
|
fun verifyShareButton() = assertShareButton()
|
||||||
@ -55,6 +56,7 @@ class ThreeDotMenuMainRobot {
|
|||||||
fun clickAddNewCollection() {
|
fun clickAddNewCollection() {
|
||||||
addNewCollectionButton().click()
|
addNewCollectionButton().click()
|
||||||
}
|
}
|
||||||
|
fun clickAddBookmarkButton() = addBookmarkButton().click()
|
||||||
fun verifyCollectionNameTextField() = assertCollectionNameTextField()
|
fun verifyCollectionNameTextField() = assertCollectionNameTextField()
|
||||||
fun verifyFindInPageButton() = assertFindInPageButton()
|
fun verifyFindInPageButton() = assertFindInPageButton()
|
||||||
fun verifyShareScrim() = assertShareScrim()
|
fun verifyShareScrim() = assertShareScrim()
|
||||||
@ -115,8 +117,10 @@ class ThreeDotMenuMainRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun goBack(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
fun goBack(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
mDevice.waitNotNull(Until.findObject(By.desc("Back")), waitingTime)
|
// Close three dot
|
||||||
backButton().click()
|
mDevice.pressBack()
|
||||||
|
// Nav back to previous page
|
||||||
|
mDevice.pressBack()
|
||||||
|
|
||||||
BrowserRobot().interact()
|
BrowserRobot().interact()
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
@ -194,8 +198,12 @@ private fun forwardButton() = onView(ViewMatchers.withContentDescription("Forwar
|
|||||||
private fun assertForwardButton() = forwardButton()
|
private fun assertForwardButton() = forwardButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun backButton() = onView(ViewMatchers.withContentDescription("Back"))
|
private fun addBookmarkButton() = onView(ViewMatchers.withContentDescription("Bookmark"))
|
||||||
private fun assertBackButton() = backButton()
|
private fun assertAddBookmarkButton() = addBookmarkButton()
|
||||||
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun editBookmarkButton() = onView(ViewMatchers.withContentDescription("Edit bookmark"))
|
||||||
|
private fun assertEditBookmarkButton() = editBookmarkButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun refreshButton() = onView(ViewMatchers.withContentDescription("Refresh"))
|
private fun refreshButton() = onView(ViewMatchers.withContentDescription("Refresh"))
|
||||||
@ -210,7 +218,7 @@ private fun shareTabButton() = onView(allOf(withText("Share tabs")))
|
|||||||
private fun assertShareTabButton() = shareTabButton()
|
private fun assertShareTabButton() = shareTabButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun shareButton() = onView(allOf(withText("Share")))
|
private fun shareButton() = onView(ViewMatchers.withContentDescription("Share"))
|
||||||
private fun assertShareButton() = shareButton()
|
private fun assertShareButton() = shareButton()
|
||||||
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.component_search.*
|
import kotlinx.android.synthetic.main.component_search.toolbar
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.*
|
import kotlinx.android.synthetic.main.fragment_browser.*
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
@ -32,6 +32,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.feature.accounts.FxaCapability
|
import mozilla.components.feature.accounts.FxaCapability
|
||||||
@ -44,6 +45,7 @@ import mozilla.components.feature.downloads.DownloadsFeature
|
|||||||
import mozilla.components.feature.downloads.manager.FetchDownloadManager
|
import mozilla.components.feature.downloads.manager.FetchDownloadManager
|
||||||
import mozilla.components.feature.intent.ext.EXTRA_SESSION_ID
|
import mozilla.components.feature.intent.ext.EXTRA_SESSION_ID
|
||||||
import mozilla.components.feature.prompts.PromptFeature
|
import mozilla.components.feature.prompts.PromptFeature
|
||||||
|
import mozilla.components.feature.readerview.ReaderViewFeature
|
||||||
import mozilla.components.feature.session.FullScreenFeature
|
import mozilla.components.feature.session.FullScreenFeature
|
||||||
import mozilla.components.feature.session.SessionFeature
|
import mozilla.components.feature.session.SessionFeature
|
||||||
import mozilla.components.feature.session.SessionUseCases
|
import mozilla.components.feature.session.SessionUseCases
|
||||||
@ -61,17 +63,17 @@ import org.mozilla.fenix.FeatureFlags
|
|||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.IntentReceiverActivity
|
import org.mozilla.fenix.IntentReceiverActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.FindInPageIntegration
|
import org.mozilla.fenix.components.FindInPageIntegration
|
||||||
import org.mozilla.fenix.components.StoreProvider
|
import org.mozilla.fenix.components.StoreProvider
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserFragmentState
|
import org.mozilla.fenix.components.toolbar.BrowserFragmentState
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserFragmentStore
|
import org.mozilla.fenix.components.toolbar.BrowserFragmentStore
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarController
|
import org.mozilla.fenix.components.toolbar.BrowserInteractor
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarView
|
import org.mozilla.fenix.components.toolbar.BrowserToolbarView
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarViewInteractor
|
import org.mozilla.fenix.components.toolbar.BrowserToolbarViewInteractor
|
||||||
import org.mozilla.fenix.components.toolbar.DefaultBrowserToolbarController
|
import org.mozilla.fenix.components.toolbar.DefaultBrowserToolbarController
|
||||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetState
|
|
||||||
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
|
import org.mozilla.fenix.components.toolbar.ToolbarIntegration
|
||||||
import org.mozilla.fenix.downloads.DownloadNotificationBottomSheetDialog
|
import org.mozilla.fenix.downloads.DownloadNotificationBottomSheetDialog
|
||||||
import org.mozilla.fenix.downloads.DownloadService
|
import org.mozilla.fenix.downloads.DownloadService
|
||||||
@ -84,7 +86,6 @@ import org.mozilla.fenix.ext.requireComponents
|
|||||||
import org.mozilla.fenix.ext.sessionsOfType
|
import org.mozilla.fenix.ext.sessionsOfType
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.isInExperiment
|
import org.mozilla.fenix.isInExperiment
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
|
|
||||||
import org.mozilla.fenix.settings.SupportUtils
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
|
|
||||||
@ -95,10 +96,12 @@ import org.mozilla.fenix.theme.ThemeManager
|
|||||||
*/
|
*/
|
||||||
@Suppress("TooManyFunctions", "LargeClass")
|
@Suppress("TooManyFunctions", "LargeClass")
|
||||||
abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Observer {
|
abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Observer {
|
||||||
protected lateinit var browserStore: BrowserFragmentStore
|
protected lateinit var browserFragmentStore: BrowserFragmentStore
|
||||||
protected lateinit var browserInteractor: BrowserToolbarViewInteractor
|
protected lateinit var browserInteractor: BrowserToolbarViewInteractor
|
||||||
protected lateinit var browserToolbarView: BrowserToolbarView
|
protected lateinit var browserToolbarView: BrowserToolbarView
|
||||||
|
|
||||||
|
protected val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewFeature>()
|
||||||
|
|
||||||
private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
|
private val sessionFeature = ViewBoundFeatureWrapper<SessionFeature>()
|
||||||
private val windowFeature = ViewBoundFeatureWrapper<WindowFeature>()
|
private val windowFeature = ViewBoundFeatureWrapper<WindowFeature>()
|
||||||
private val contextMenuFeature = ViewBoundFeatureWrapper<ContextMenuFeature>()
|
private val contextMenuFeature = ViewBoundFeatureWrapper<ContextMenuFeature>()
|
||||||
@ -131,20 +134,9 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
val activity = activity as HomeActivity
|
val activity = activity as HomeActivity
|
||||||
activity.themeManager.applyStatusBarTheme(activity)
|
activity.themeManager.applyStatusBarTheme(activity)
|
||||||
|
|
||||||
val appLink = requireComponents.useCases.appLinksUseCases.appLinkRedirect
|
browserFragmentStore = StoreProvider.get(this) {
|
||||||
browserStore = StoreProvider.get(this) {
|
|
||||||
BrowserFragmentStore(
|
BrowserFragmentStore(
|
||||||
BrowserFragmentState(
|
BrowserFragmentState()
|
||||||
quickActionSheetState = QuickActionSheetState(
|
|
||||||
readable = getSessionById()?.readerable ?: false,
|
|
||||||
bookmarked = false,
|
|
||||||
readerActive = getSessionById()?.readerMode ?: false,
|
|
||||||
bounceNeeded = false,
|
|
||||||
isAppLink = getSessionById()?.let {
|
|
||||||
appLink.invoke(it.url).hasExternalApp()
|
|
||||||
} ?: false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,10 +165,13 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
}
|
}
|
||||||
|
|
||||||
val browserToolbarController = DefaultBrowserToolbarController(
|
val browserToolbarController = DefaultBrowserToolbarController(
|
||||||
requireActivity(),
|
store = browserFragmentStore,
|
||||||
snackbar,
|
activity = requireActivity(),
|
||||||
findNavController(),
|
snackbar = snackbar,
|
||||||
(activity as HomeActivity).browsingModeManager,
|
navController = findNavController(),
|
||||||
|
readerModeController = DefaultReaderModeController(readerViewFeature),
|
||||||
|
browsingModeManager = (activity as HomeActivity).browsingModeManager,
|
||||||
|
sessionManager = requireComponents.core.sessionManager,
|
||||||
findInPageLauncher = { findInPageIntegration.withFeature { it.launch() } },
|
findInPageLauncher = { findInPageIntegration.withFeature { it.launch() } },
|
||||||
browserLayout = view.browserLayout,
|
browserLayout = view.browserLayout,
|
||||||
engineView = engineView,
|
engineView = engineView,
|
||||||
@ -193,15 +188,14 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
},
|
},
|
||||||
bottomSheetBehavior = QuickActionSheetBehavior.from(nestedScrollQuickAction),
|
bookmarkTapped = { lifecycleScope.launch { bookmarkTapped(it) } },
|
||||||
scope = lifecycleScope,
|
scope = lifecycleScope,
|
||||||
tabCollectionStorage = requireComponents.core.tabCollectionStorage
|
tabCollectionStorage = requireComponents.core.tabCollectionStorage
|
||||||
)
|
)
|
||||||
|
|
||||||
browserInteractor =
|
browserInteractor = BrowserInteractor(
|
||||||
createBrowserToolbarViewInteractor(
|
browserToolbarController = browserToolbarController
|
||||||
browserToolbarController,
|
)
|
||||||
customTabSessionId?.let { sessionManager.findSessionById(it) })
|
|
||||||
|
|
||||||
browserToolbarView = BrowserToolbarView(
|
browserToolbarView = BrowserToolbarView(
|
||||||
container = view.browserLayout,
|
container = view.browserLayout,
|
||||||
@ -368,7 +362,6 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||||
activity?.enterToImmersiveMode()
|
activity?.enterToImmersiveMode()
|
||||||
toolbar.visibility = View.GONE
|
toolbar.visibility = View.GONE
|
||||||
nestedScrollQuickAction.visibility = View.GONE
|
|
||||||
} else {
|
} else {
|
||||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||||
activity?.exitImmersiveModeIfNeeded()
|
activity?.exitImmersiveModeIfNeeded()
|
||||||
@ -376,7 +369,6 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
activity.themeManager.applyStatusBarTheme(activity)
|
activity.themeManager.applyStatusBarTheme(activity)
|
||||||
}
|
}
|
||||||
toolbar.visibility = View.VISIBLE
|
toolbar.visibility = View.VISIBLE
|
||||||
nestedScrollQuickAction.visibility = View.VISIBLE
|
|
||||||
}
|
}
|
||||||
updateLayoutMargins(inFullScreen)
|
updateLayoutMargins(inFullScreen)
|
||||||
},
|
},
|
||||||
@ -557,11 +549,6 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun createBrowserToolbarViewInteractor(
|
|
||||||
browserToolbarController: BrowserToolbarController,
|
|
||||||
session: Session?
|
|
||||||
): BrowserToolbarViewInteractor
|
|
||||||
|
|
||||||
protected abstract fun navToQuickSettingsSheet(
|
protected abstract fun navToQuickSettingsSheet(
|
||||||
session: Session,
|
session: Session,
|
||||||
sitePermissions: SitePermissions?
|
sitePermissions: SitePermissions?
|
||||||
@ -644,6 +631,48 @@ abstract class BaseBrowserFragment : Fragment(), BackHandler, SessionManager.Obs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun bookmarkTapped(session: Session) = withContext(IO) {
|
||||||
|
val bookmarksStorage = requireComponents.core.bookmarksStorage
|
||||||
|
val existing =
|
||||||
|
bookmarksStorage.getBookmarksWithUrl(session.url).firstOrNull { it.url == session.url }
|
||||||
|
if (existing != null) {
|
||||||
|
// Bookmark exists, go to edit fragment
|
||||||
|
withContext(Main) {
|
||||||
|
nav(
|
||||||
|
R.id.browserFragment,
|
||||||
|
BrowserFragmentDirections.actionBrowserFragmentToBookmarkEditFragment(existing.guid)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Save bookmark, then go to edit fragment
|
||||||
|
val guid = bookmarksStorage.addItem(
|
||||||
|
BookmarkRoot.Mobile.id,
|
||||||
|
url = session.url,
|
||||||
|
title = session.title,
|
||||||
|
position = null
|
||||||
|
)
|
||||||
|
|
||||||
|
withContext(Main) {
|
||||||
|
requireComponents.analytics.metrics.track(Event.AddBookmark)
|
||||||
|
|
||||||
|
view?.let { view ->
|
||||||
|
FenixSnackbar.make(view, Snackbar.LENGTH_LONG)
|
||||||
|
.setAnchorView(browserToolbarView.view)
|
||||||
|
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
|
||||||
|
nav(
|
||||||
|
R.id.browserFragment,
|
||||||
|
BrowserFragmentDirections.actionBrowserFragmentToBookmarkEditFragment(
|
||||||
|
guid
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.setText(getString(R.string.bookmark_saved_snackbar))
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_CUSTOM_TAB_SESSION_ID = "custom_tab_session_id"
|
private const val KEY_CUSTOM_TAB_SESSION_ID = "custom_tab_session_id"
|
||||||
private const val REQUEST_CODE_DOWNLOAD_PERMISSIONS = 1
|
private const val REQUEST_CODE_DOWNLOAD_PERMISSIONS = 1
|
||||||
|
@ -20,19 +20,13 @@ import android.widget.RadioButton
|
|||||||
import androidx.appcompat.widget.AppCompatImageView
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.transition.TransitionInflater
|
import androidx.transition.TransitionInflater
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.*
|
import kotlinx.android.synthetic.main.fragment_browser.view.browserLayout
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
import kotlinx.android.synthetic.main.fragment_browser.view.readerViewControlsBar
|
||||||
import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.*
|
import kotlinx.android.synthetic.main.fragment_home.bottom_bar
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.onboarding_message
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.feature.contextmenu.ContextMenuCandidate
|
import mozilla.components.feature.contextmenu.ContextMenuCandidate
|
||||||
import mozilla.components.feature.readerview.ReaderViewFeature
|
import mozilla.components.feature.readerview.ReaderViewFeature
|
||||||
@ -40,18 +34,12 @@ import mozilla.components.feature.session.TrackingProtectionUseCases
|
|||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import mozilla.components.lib.state.ext.consumeFrom
|
import mozilla.components.lib.state.ext.consumeFrom
|
||||||
import mozilla.components.support.base.feature.BackHandler
|
import mozilla.components.support.base.feature.BackHandler
|
||||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
|
||||||
import org.jetbrains.anko.dimen
|
import org.jetbrains.anko.dimen
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
|
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.TabCollectionStorage
|
import org.mozilla.fenix.components.TabCollectionStorage
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserInteractor
|
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarController
|
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarViewInteractor
|
|
||||||
import org.mozilla.fenix.components.toolbar.QuickActionSheetAction
|
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.getDimenInDip
|
import org.mozilla.fenix.ext.getDimenInDip
|
||||||
import org.mozilla.fenix.ext.increaseTapArea
|
import org.mozilla.fenix.ext.increaseTapArea
|
||||||
@ -61,9 +49,6 @@ import org.mozilla.fenix.ext.settings
|
|||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlChange
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlChange
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||||
import org.mozilla.fenix.quickactionsheet.DefaultQuickActionSheetController
|
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetSessionObserver
|
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetView
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment used for browsing the web within the main app.
|
* Fragment used for browsing the web within the main app.
|
||||||
@ -71,10 +56,6 @@ import org.mozilla.fenix.quickactionsheet.QuickActionSheetView
|
|||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
@Suppress("TooManyFunctions", "LargeClass")
|
@Suppress("TooManyFunctions", "LargeClass")
|
||||||
class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
||||||
private lateinit var quickActionSheetView: QuickActionSheetView
|
|
||||||
private var quickActionSheetSessionObserver: QuickActionSheetSessionObserver? = null
|
|
||||||
|
|
||||||
private val readerViewFeature = ViewBoundFeatureWrapper<ReaderViewFeature>()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -114,15 +95,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
if (available) {
|
if (available) {
|
||||||
context.components.analytics.metrics.track(Event.ReaderModeAvailable)
|
context.components.analytics.metrics.track(Event.ReaderModeAvailable)
|
||||||
}
|
}
|
||||||
|
|
||||||
browserStore.apply {
|
|
||||||
dispatch(QuickActionSheetAction.ReadableStateChange(available))
|
|
||||||
dispatch(
|
|
||||||
QuickActionSheetAction.ReaderActiveStateChange(
|
|
||||||
sessionManager.selectedSession?.readerMode ?: false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
@ -134,8 +106,7 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
themeReaderViewControlsForPrivateMode(view.readerViewControlsBar)
|
themeReaderViewControlsForPrivateMode(view.readerViewControlsBar)
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeFrom(browserStore) {
|
consumeFrom(browserFragmentStore) {
|
||||||
quickActionSheetView.update(it)
|
|
||||||
browserToolbarView.update(it)
|
browserToolbarView.update(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,13 +115,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
subscribeToTabCollections()
|
subscribeToTabCollections()
|
||||||
quickActionSheetSessionObserver = QuickActionSheetSessionObserver(
|
|
||||||
lifecycleScope,
|
|
||||||
requireComponents,
|
|
||||||
dispatch = { action -> browserStore.dispatch(action) }
|
|
||||||
).also { observer ->
|
|
||||||
getSessionById()?.register(observer, this, autoPause = true)
|
|
||||||
}
|
|
||||||
getSessionById()?.register(toolbarSessionObserver, this, autoPause = true)
|
getSessionById()?.register(toolbarSessionObserver, this, autoPause = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +137,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
* This fixes issue #5254.
|
* This fixes issue #5254.
|
||||||
*/
|
*/
|
||||||
(activity as HomeActivity).updateThemeForSession(it)
|
(activity as HomeActivity).updateThemeForSession(it)
|
||||||
quickActionSheetSessionObserver?.updateBookmarkState(it)
|
|
||||||
}
|
}
|
||||||
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
||||||
}
|
}
|
||||||
@ -182,34 +145,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
return readerViewFeature.onBackPressed() || super.onBackPressed()
|
return readerViewFeature.onBackPressed() || super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBrowserToolbarViewInteractor(
|
|
||||||
browserToolbarController: BrowserToolbarController,
|
|
||||||
session: Session?
|
|
||||||
): BrowserToolbarViewInteractor {
|
|
||||||
val context = requireContext()
|
|
||||||
|
|
||||||
val interactor = BrowserInteractor(
|
|
||||||
context = context,
|
|
||||||
store = browserStore,
|
|
||||||
browserToolbarController = browserToolbarController,
|
|
||||||
quickActionSheetController = DefaultQuickActionSheetController(
|
|
||||||
context = context,
|
|
||||||
navController = findNavController(),
|
|
||||||
sessionManager = context.components.core.sessionManager,
|
|
||||||
appLinksUseCases = context.components.useCases.appLinksUseCases,
|
|
||||||
bookmarkTapped = {
|
|
||||||
lifecycleScope.launch { bookmarkTapped(it) }
|
|
||||||
}
|
|
||||||
),
|
|
||||||
readerModeController = DefaultReaderModeController(readerViewFeature),
|
|
||||||
currentSession = session
|
|
||||||
)
|
|
||||||
|
|
||||||
quickActionSheetView = QuickActionSheetView(view!!.nestedScrollQuickAction, interactor)
|
|
||||||
|
|
||||||
return interactor
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) {
|
override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) {
|
||||||
val directions =
|
val directions =
|
||||||
BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment(
|
BrowserFragmentDirections.actionBrowserFragmentToQuickSettingsSheetDialogFragment(
|
||||||
@ -241,8 +176,8 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getEngineMargins(): Pair<Int, Int> {
|
override fun getEngineMargins(): Pair<Int, Int> {
|
||||||
val toolbarAndQASSize = resources.getDimensionPixelSize(R.dimen.toolbar_and_qab_height)
|
val toolbarSize = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height)
|
||||||
return 0 to toolbarAndQASSize
|
return 0 to toolbarSize
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAppropriateLayoutGravity() = Gravity.BOTTOM
|
override fun getAppropriateLayoutGravity() = Gravity.BOTTOM
|
||||||
@ -277,51 +212,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun bookmarkTapped(session: Session) = withContext(IO) {
|
|
||||||
val bookmarksStorage = requireComponents.core.bookmarksStorage
|
|
||||||
val existing =
|
|
||||||
bookmarksStorage.getBookmarksWithUrl(session.url).firstOrNull { it.url == session.url }
|
|
||||||
if (existing != null) {
|
|
||||||
// Bookmark exists, go to edit fragment
|
|
||||||
withContext(Main) {
|
|
||||||
nav(
|
|
||||||
R.id.browserFragment,
|
|
||||||
BrowserFragmentDirections.actionBrowserFragmentToBookmarkEditFragment(existing.guid)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Save bookmark, then go to edit fragment
|
|
||||||
val guid = bookmarksStorage.addItem(
|
|
||||||
BookmarkRoot.Mobile.id,
|
|
||||||
url = session.url,
|
|
||||||
title = session.title,
|
|
||||||
position = null
|
|
||||||
)
|
|
||||||
|
|
||||||
withContext(Main) {
|
|
||||||
browserStore.dispatch(
|
|
||||||
QuickActionSheetAction.BookmarkedStateChange(bookmarked = true)
|
|
||||||
)
|
|
||||||
requireComponents.analytics.metrics.track(Event.AddBookmark)
|
|
||||||
|
|
||||||
view?.let { view ->
|
|
||||||
FenixSnackbar.make(view, Snackbar.LENGTH_LONG)
|
|
||||||
.setAnchorView(browserToolbarView.view)
|
|
||||||
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
|
|
||||||
nav(
|
|
||||||
R.id.browserFragment,
|
|
||||||
BrowserFragmentDirections.actionBrowserFragmentToBookmarkEditFragment(
|
|
||||||
guid
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.setText(getString(R.string.bookmark_saved_snackbar))
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeToTabCollections() {
|
private fun subscribeToTabCollections() {
|
||||||
requireComponents.core.tabCollectionStorage.getCollections().observe(this, Observer {
|
requireComponents.core.tabCollectionStorage.getCollections().observe(this, Observer {
|
||||||
requireComponents.core.tabCollectionStorage.cachedTabCollections = it
|
requireComponents.core.tabCollectionStorage.cachedTabCollections = it
|
||||||
@ -333,11 +223,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSessionSelected(session: Session) {
|
|
||||||
super.onSessionSelected(session)
|
|
||||||
quickActionSheetSessionObserver?.updateBookmarkState(session)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val collectionStorageObserver = object : TabCollectionStorage.Observer {
|
private val collectionStorageObserver = object : TabCollectionStorage.Observer {
|
||||||
override fun onCollectionCreated(title: String, sessions: List<Session>) {
|
override fun onCollectionCreated(title: String, sessions: List<Session>) {
|
||||||
showTabSavedToCollectionSnackbar()
|
showTabSavedToCollectionSnackbar()
|
||||||
@ -415,7 +300,7 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
view,
|
view,
|
||||||
FenixSnackbarDelegate(
|
FenixSnackbarDelegate(
|
||||||
view,
|
view,
|
||||||
nestedScrollQuickAction
|
bottom_bar
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ import org.mozilla.fenix.GleanMetrics.Pings
|
|||||||
import org.mozilla.fenix.GleanMetrics.PrivateBrowsingMode
|
import org.mozilla.fenix.GleanMetrics.PrivateBrowsingMode
|
||||||
import org.mozilla.fenix.GleanMetrics.PrivateBrowsingShortcut
|
import org.mozilla.fenix.GleanMetrics.PrivateBrowsingShortcut
|
||||||
import org.mozilla.fenix.GleanMetrics.QrScanner
|
import org.mozilla.fenix.GleanMetrics.QrScanner
|
||||||
import org.mozilla.fenix.GleanMetrics.QuickActionSheet
|
|
||||||
import org.mozilla.fenix.GleanMetrics.ReaderMode
|
import org.mozilla.fenix.GleanMetrics.ReaderMode
|
||||||
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
|
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
|
||||||
import org.mozilla.fenix.GleanMetrics.SearchShortcuts
|
import org.mozilla.fenix.GleanMetrics.SearchShortcuts
|
||||||
@ -138,24 +137,6 @@ private val Event.wrapper: EventWrapper<*>?
|
|||||||
{ Events.browserMenuAction.record(it) },
|
{ Events.browserMenuAction.record(it) },
|
||||||
{ Events.browserMenuActionKeys.valueOf(it) }
|
{ Events.browserMenuActionKeys.valueOf(it) }
|
||||||
)
|
)
|
||||||
is Event.QuickActionSheetOpened -> EventWrapper<NoExtraKeys>(
|
|
||||||
{ QuickActionSheet.opened.record(it) }
|
|
||||||
)
|
|
||||||
is Event.QuickActionSheetClosed -> EventWrapper<NoExtraKeys>(
|
|
||||||
{ QuickActionSheet.closed.record(it) }
|
|
||||||
)
|
|
||||||
is Event.QuickActionSheetShareTapped -> EventWrapper<NoExtraKeys>(
|
|
||||||
{ QuickActionSheet.shareTapped.record(it) }
|
|
||||||
)
|
|
||||||
is Event.QuickActionSheetBookmarkTapped -> EventWrapper<NoExtraKeys>(
|
|
||||||
{ QuickActionSheet.bookmarkTapped.record(it) }
|
|
||||||
)
|
|
||||||
is Event.QuickActionSheetDownloadTapped -> EventWrapper<NoExtraKeys>(
|
|
||||||
{ QuickActionSheet.downloadTapped.record(it) }
|
|
||||||
)
|
|
||||||
is Event.QuickActionSheetOpenInAppTapped -> EventWrapper<NoExtraKeys>(
|
|
||||||
{ QuickActionSheet.openAppTapped.record(it) }
|
|
||||||
)
|
|
||||||
is Event.OpenedBookmarkInNewTab -> EventWrapper<NoExtraKeys>(
|
is Event.OpenedBookmarkInNewTab -> EventWrapper<NoExtraKeys>(
|
||||||
{ BookmarksManagement.openInNewTab.record(it) }
|
{ BookmarksManagement.openInNewTab.record(it) }
|
||||||
)
|
)
|
||||||
|
@ -50,12 +50,6 @@ sealed class Event {
|
|||||||
object AddBookmarkFolder : Event()
|
object AddBookmarkFolder : Event()
|
||||||
object RemoveBookmarkFolder : Event()
|
object RemoveBookmarkFolder : Event()
|
||||||
object RemoveBookmarks : Event()
|
object RemoveBookmarks : Event()
|
||||||
object QuickActionSheetOpened : Event()
|
|
||||||
object QuickActionSheetClosed : Event()
|
|
||||||
object QuickActionSheetShareTapped : Event()
|
|
||||||
object QuickActionSheetBookmarkTapped : Event()
|
|
||||||
object QuickActionSheetDownloadTapped : Event()
|
|
||||||
object QuickActionSheetOpenInAppTapped : Event()
|
|
||||||
object CustomTabsClosed : Event()
|
object CustomTabsClosed : Event()
|
||||||
object CustomTabsActionTapped : Event()
|
object CustomTabsActionTapped : Event()
|
||||||
object CustomTabsMenuOpened : Event()
|
object CustomTabsMenuOpened : Event()
|
||||||
@ -300,7 +294,8 @@ sealed class Event {
|
|||||||
enum class Item {
|
enum class Item {
|
||||||
SETTINGS, LIBRARY, HELP, DESKTOP_VIEW_ON, DESKTOP_VIEW_OFF, FIND_IN_PAGE, NEW_TAB,
|
SETTINGS, LIBRARY, HELP, DESKTOP_VIEW_ON, DESKTOP_VIEW_OFF, FIND_IN_PAGE, NEW_TAB,
|
||||||
NEW_PRIVATE_TAB, SHARE, REPORT_SITE_ISSUE, BACK, FORWARD, RELOAD, STOP, OPEN_IN_FENIX,
|
NEW_PRIVATE_TAB, SHARE, REPORT_SITE_ISSUE, BACK, FORWARD, RELOAD, STOP, OPEN_IN_FENIX,
|
||||||
SAVE_TO_COLLECTION, ADD_TO_HOMESCREEN, QUIT
|
SAVE_TO_COLLECTION, ADD_TO_HOMESCREEN, QUIT, READER_MODE_ON, READER_MODE_OFF, OPEN_IN_APP,
|
||||||
|
BOOKMARK, READER_MODE_APPEARANCE
|
||||||
}
|
}
|
||||||
|
|
||||||
override val extras: Map<Events.browserMenuActionKeys, String>?
|
override val extras: Map<Events.browserMenuActionKeys, String>?
|
||||||
|
@ -2,51 +2,27 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
@file:Suppress("unused", "UNUSED_PARAMETER")
|
||||||
|
|
||||||
package org.mozilla.fenix.components.toolbar
|
package org.mozilla.fenix.components.toolbar
|
||||||
|
|
||||||
import mozilla.components.lib.state.Action
|
import mozilla.components.lib.state.Action
|
||||||
import mozilla.components.lib.state.State
|
import mozilla.components.lib.state.State
|
||||||
import mozilla.components.lib.state.Store
|
import mozilla.components.lib.state.Store
|
||||||
|
|
||||||
|
// The state that used to live in this class was moved into another component in #4281. Keeping
|
||||||
|
// the shell of this file because we will need to expand it as we add additional features to
|
||||||
|
// the browser.
|
||||||
class BrowserFragmentStore(initialState: BrowserFragmentState) :
|
class BrowserFragmentStore(initialState: BrowserFragmentState) :
|
||||||
Store<BrowserFragmentState, BrowserFragmentAction>(initialState, ::browserStateReducer)
|
Store<BrowserFragmentState, BrowserFragmentAction>(initialState, ::browserStateReducer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state for the Browser Screen
|
* The state for the Browser Screen
|
||||||
* @property quickActionSheetState: state of the quick action sheet
|
|
||||||
*/
|
*/
|
||||||
data class BrowserFragmentState(
|
class BrowserFragmentState : State
|
||||||
val quickActionSheetState: QuickActionSheetState
|
|
||||||
) : State
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The state for the QuickActionSheet
|
|
||||||
* @property readable Whether or not the current session can display a reader view
|
|
||||||
* @property bookmarked Whether or not the current session is already bookmarked
|
|
||||||
* @property readerActive Whether or not the current session is in reader mode
|
|
||||||
* @property bounceNeeded Whether or not the quick action sheet should bounce
|
|
||||||
*/
|
|
||||||
data class QuickActionSheetState(
|
|
||||||
val readable: Boolean,
|
|
||||||
val bookmarked: Boolean,
|
|
||||||
val readerActive: Boolean,
|
|
||||||
val bounceNeeded: Boolean,
|
|
||||||
val isAppLink: Boolean
|
|
||||||
) : State
|
|
||||||
|
|
||||||
sealed class BrowserFragmentAction : Action
|
sealed class BrowserFragmentAction : Action
|
||||||
|
|
||||||
/**
|
|
||||||
* Actions to dispatch through the [QuickActionSheetStore] to modify [QuickActionSheetState] through the reducer.
|
|
||||||
*/
|
|
||||||
sealed class QuickActionSheetAction : BrowserFragmentAction() {
|
|
||||||
data class BookmarkedStateChange(val bookmarked: Boolean) : QuickActionSheetAction()
|
|
||||||
data class ReadableStateChange(val readable: Boolean) : QuickActionSheetAction()
|
|
||||||
data class ReaderActiveStateChange(val active: Boolean) : QuickActionSheetAction()
|
|
||||||
data class AppLinkStateChange(val isAppLink: Boolean) : QuickActionSheetAction()
|
|
||||||
object BounceNeededChange : QuickActionSheetAction()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reducers for [BrowserFragmentStore].
|
* Reducers for [BrowserFragmentStore].
|
||||||
*
|
*
|
||||||
@ -57,30 +33,7 @@ private fun browserStateReducer(
|
|||||||
state: BrowserFragmentState,
|
state: BrowserFragmentState,
|
||||||
action: BrowserFragmentAction
|
action: BrowserFragmentAction
|
||||||
): BrowserFragmentState {
|
): BrowserFragmentState {
|
||||||
return when (action) {
|
return when {
|
||||||
is QuickActionSheetAction -> {
|
else -> BrowserFragmentState()
|
||||||
QuickActionSheetStateReducer.reduce(state, action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reduces [QuickActionSheetAction]s to update [BrowserFragmentState].
|
|
||||||
*/
|
|
||||||
internal object QuickActionSheetStateReducer {
|
|
||||||
fun reduce(state: BrowserFragmentState, action: QuickActionSheetAction): BrowserFragmentState {
|
|
||||||
return when (action) {
|
|
||||||
is QuickActionSheetAction.BookmarkedStateChange ->
|
|
||||||
state.copy(quickActionSheetState = state.quickActionSheetState.copy(bookmarked = action.bookmarked))
|
|
||||||
is QuickActionSheetAction.ReadableStateChange ->
|
|
||||||
state.copy(quickActionSheetState = state.quickActionSheetState.copy(readable = action.readable))
|
|
||||||
is QuickActionSheetAction.ReaderActiveStateChange ->
|
|
||||||
state.copy(quickActionSheetState = state.quickActionSheetState.copy(readerActive = action.active))
|
|
||||||
is QuickActionSheetAction.BounceNeededChange ->
|
|
||||||
state.copy(quickActionSheetState = state.quickActionSheetState.copy(bounceNeeded = true))
|
|
||||||
is QuickActionSheetAction.AppLinkStateChange -> {
|
|
||||||
state.copy(quickActionSheetState = state.quickActionSheetState.copy(isAppLink = action.isAppLink))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,7 @@
|
|||||||
|
|
||||||
package org.mozilla.fenix.components.toolbar
|
package org.mozilla.fenix.components.toolbar
|
||||||
|
|
||||||
import android.content.Context
|
open class BrowserInteractor(
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetController
|
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetViewInteractor
|
|
||||||
|
|
||||||
open class BrowserToolbarInteractor(
|
|
||||||
private val browserToolbarController: BrowserToolbarController
|
private val browserToolbarController: BrowserToolbarController
|
||||||
) : BrowserToolbarViewInteractor {
|
) : BrowserToolbarViewInteractor {
|
||||||
|
|
||||||
@ -37,56 +28,3 @@ open class BrowserToolbarInteractor(
|
|||||||
browserToolbarController.handleToolbarItemInteraction(item)
|
browserToolbarController.handleToolbarItemInteraction(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrowserInteractor(
|
|
||||||
private val context: Context,
|
|
||||||
private val store: BrowserFragmentStore,
|
|
||||||
browserToolbarController: BrowserToolbarController,
|
|
||||||
private val quickActionSheetController: QuickActionSheetController,
|
|
||||||
private val readerModeController: ReaderModeController,
|
|
||||||
private val currentSession: Session?
|
|
||||||
) : BrowserToolbarInteractor(browserToolbarController), QuickActionSheetViewInteractor {
|
|
||||||
|
|
||||||
override fun onQuickActionSheetOpened() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetOpened)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetClosed() {
|
|
||||||
context.metrics.track(Event.QuickActionSheetClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetSharePressed() {
|
|
||||||
quickActionSheetController.handleShare()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetDownloadPressed() {
|
|
||||||
quickActionSheetController.handleDownload()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetBookmarkPressed() {
|
|
||||||
quickActionSheetController.handleBookmark()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetReadPressed() {
|
|
||||||
val enabled =
|
|
||||||
currentSession?.readerMode ?: context.components.core.sessionManager.selectedSession?.readerMode ?: false
|
|
||||||
|
|
||||||
if (enabled) {
|
|
||||||
context.metrics.track(Event.QuickActionSheetClosed)
|
|
||||||
readerModeController.hideReaderView()
|
|
||||||
} else {
|
|
||||||
context.metrics.track(Event.QuickActionSheetOpened)
|
|
||||||
readerModeController.showReaderView()
|
|
||||||
}
|
|
||||||
store.dispatch(QuickActionSheetAction.ReaderActiveStateChange(!enabled))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetOpenLinkPressed() {
|
|
||||||
quickActionSheetController.handleOpenLink()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQuickActionSheetAppearancePressed() {
|
|
||||||
context.metrics.track(Event.ReaderModeAppearanceOpened)
|
|
||||||
readerModeController.showControls()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -11,18 +11,17 @@ import android.graphics.drawable.ColorDrawable
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.fragment.FragmentNavigator
|
import androidx.navigation.fragment.FragmentNavigator
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.concept.engine.EngineView
|
import mozilla.components.concept.engine.EngineView
|
||||||
import mozilla.components.support.ktx.kotlin.isUrl
|
import mozilla.components.support.ktx.kotlin.isUrl
|
||||||
import org.mozilla.fenix.NavGraphDirections
|
import org.mozilla.fenix.NavGraphDirections
|
||||||
@ -31,14 +30,14 @@ import org.mozilla.fenix.browser.BrowserFragment
|
|||||||
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
import org.mozilla.fenix.browser.BrowserFragmentDirections
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
||||||
import org.mozilla.fenix.collections.SaveCollectionStep
|
import org.mozilla.fenix.collections.SaveCollectionStep
|
||||||
import org.mozilla.fenix.components.TabCollectionStorage
|
import org.mozilla.fenix.components.TabCollectionStorage
|
||||||
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
import org.mozilla.fenix.lib.Do
|
import org.mozilla.fenix.lib.Do
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
|
|
||||||
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
|
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,10 +53,13 @@ interface BrowserToolbarController {
|
|||||||
|
|
||||||
@Suppress("LargeClass")
|
@Suppress("LargeClass")
|
||||||
class DefaultBrowserToolbarController(
|
class DefaultBrowserToolbarController(
|
||||||
|
private val store: BrowserFragmentStore,
|
||||||
private val activity: Activity,
|
private val activity: Activity,
|
||||||
private val snackbar: FenixSnackbar?,
|
private val snackbar: FenixSnackbar?,
|
||||||
private val navController: NavController,
|
private val navController: NavController,
|
||||||
|
private val readerModeController: ReaderModeController,
|
||||||
private val browsingModeManager: BrowsingModeManager,
|
private val browsingModeManager: BrowsingModeManager,
|
||||||
|
private val sessionManager: SessionManager,
|
||||||
private val findInPageLauncher: () -> Unit,
|
private val findInPageLauncher: () -> Unit,
|
||||||
private val browserLayout: ViewGroup,
|
private val browserLayout: ViewGroup,
|
||||||
private val engineView: EngineView,
|
private val engineView: EngineView,
|
||||||
@ -66,7 +68,7 @@ class DefaultBrowserToolbarController(
|
|||||||
private val customTabSession: Session?,
|
private val customTabSession: Session?,
|
||||||
private val getSupportUrl: () -> String,
|
private val getSupportUrl: () -> String,
|
||||||
private val openInFenixIntent: Intent,
|
private val openInFenixIntent: Intent,
|
||||||
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView>,
|
private val bookmarkTapped: (Session) -> Unit,
|
||||||
private val scope: LifecycleCoroutineScope,
|
private val scope: LifecycleCoroutineScope,
|
||||||
private val tabCollectionStorage: TabCollectionStorage
|
private val tabCollectionStorage: TabCollectionStorage
|
||||||
) : BrowserToolbarController {
|
) : BrowserToolbarController {
|
||||||
@ -163,7 +165,6 @@ class DefaultBrowserToolbarController(
|
|||||||
browsingModeManager.mode = BrowsingMode.Private
|
browsingModeManager.mode = BrowsingMode.Private
|
||||||
}
|
}
|
||||||
ToolbarMenu.Item.FindInPage -> {
|
ToolbarMenu.Item.FindInPage -> {
|
||||||
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
findInPageLauncher()
|
findInPageLauncher()
|
||||||
activity.components.analytics.metrics.track(Event.FindInPageOpened)
|
activity.components.analytics.metrics.track(Event.FindInPageOpened)
|
||||||
}
|
}
|
||||||
@ -210,6 +211,35 @@ class DefaultBrowserToolbarController(
|
|||||||
activity.finish()
|
activity.finish()
|
||||||
}
|
}
|
||||||
ToolbarMenu.Item.Quit -> deleteAndQuit(activity, scope, snackbar)
|
ToolbarMenu.Item.Quit -> deleteAndQuit(activity, scope, snackbar)
|
||||||
|
is ToolbarMenu.Item.ReaderMode -> {
|
||||||
|
val enabled = currentSession?.readerMode
|
||||||
|
?: activity.components.core.sessionManager.selectedSession?.readerMode
|
||||||
|
?: false
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
readerModeController.hideReaderView()
|
||||||
|
} else {
|
||||||
|
readerModeController.showReaderView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.ReaderModeAppearance -> {
|
||||||
|
readerModeController.showControls()
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.OpenInApp -> {
|
||||||
|
val appLinksUseCases =
|
||||||
|
activity.components.useCases.appLinksUseCases
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.Bookmark -> {
|
||||||
|
sessionManager.selectedSession?.let {
|
||||||
|
bookmarkTapped(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +290,16 @@ class DefaultBrowserToolbarController(
|
|||||||
ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
|
ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
|
||||||
ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
|
ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
|
||||||
ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
|
ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
|
||||||
|
is ToolbarMenu.Item.ReaderMode ->
|
||||||
|
if (item.isChecked) {
|
||||||
|
Event.BrowserMenuItemTapped.Item.READER_MODE_ON
|
||||||
|
} else {
|
||||||
|
Event.BrowserMenuItemTapped.Item.READER_MODE_OFF
|
||||||
|
}
|
||||||
|
ToolbarMenu.Item.ReaderModeAppearance ->
|
||||||
|
Event.BrowserMenuItemTapped.Item.READER_MODE_APPEARANCE
|
||||||
|
ToolbarMenu.Item.OpenInApp -> Event.BrowserMenuItemTapped.Item.OPEN_IN_APP
|
||||||
|
ToolbarMenu.Item.Bookmark -> Event.BrowserMenuItemTapped.Item.BOOKMARK
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem))
|
activity.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem))
|
||||||
|
@ -10,11 +10,14 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.PopupWindow
|
import android.widget.PopupWindow
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
import kotlinx.android.synthetic.main.browser_toolbar_popup_window.view.*
|
import kotlinx.android.synthetic.main.browser_toolbar_popup_window.view.copy
|
||||||
|
import kotlinx.android.synthetic.main.browser_toolbar_popup_window.view.paste
|
||||||
|
import kotlinx.android.synthetic.main.browser_toolbar_popup_window.view.paste_and_go
|
||||||
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.browser.toolbar.BrowserToolbar
|
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||||
@ -24,6 +27,7 @@ import org.jetbrains.anko.dimen
|
|||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.customtabs.CustomTabToolbarMenu
|
import org.mozilla.fenix.customtabs.CustomTabToolbarMenu
|
||||||
|
import org.mozilla.fenix.ext.bookmarkStorage
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
|
|
||||||
@ -168,12 +172,18 @@ class BrowserToolbarView(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
DefaultToolbarMenu(
|
DefaultToolbarMenu(
|
||||||
this,
|
context = this,
|
||||||
hasAccountProblem = components.backgroundServices.accountManager.accountNeedsReauth(),
|
hasAccountProblem = components.backgroundServices.accountManager.accountNeedsReauth(),
|
||||||
requestDesktopStateProvider = {
|
requestDesktopStateProvider = {
|
||||||
sessionManager.selectedSession?.desktopMode ?: false
|
sessionManager.selectedSession?.desktopMode ?: false
|
||||||
},
|
},
|
||||||
onItemTapped = { interactor.onBrowserToolbarMenuItemTapped(it) }
|
readerModeStateProvider = {
|
||||||
|
sessionManager.selectedSession?.readerMode ?: false
|
||||||
|
},
|
||||||
|
onItemTapped = { interactor.onBrowserToolbarMenuItemTapped(it) },
|
||||||
|
lifecycleOwner = container.context as AppCompatActivity,
|
||||||
|
sessionManager = sessionManager,
|
||||||
|
bookmarksStorage = bookmarkStorage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,19 @@
|
|||||||
package org.mozilla.fenix.components.toolbar
|
package org.mozilla.fenix.components.toolbar
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||||
import mozilla.components.browser.menu.item.BrowserMenuDivider
|
import mozilla.components.browser.menu.item.BrowserMenuDivider
|
||||||
import mozilla.components.browser.menu.item.BrowserMenuHighlightableItem
|
import mozilla.components.browser.menu.item.BrowserMenuHighlightableItem
|
||||||
import mozilla.components.browser.menu.item.BrowserMenuImageText
|
import mozilla.components.browser.menu.item.BrowserMenuImageText
|
||||||
import mozilla.components.browser.menu.item.BrowserMenuItemToolbar
|
import mozilla.components.browser.menu.item.BrowserMenuItemToolbar
|
||||||
import mozilla.components.browser.menu.item.BrowserMenuImageSwitch
|
import mozilla.components.browser.menu.item.BrowserMenuImageSwitch
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import mozilla.components.browser.session.SessionManager
|
||||||
|
import mozilla.components.concept.storage.BookmarksStorage
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
@ -19,35 +26,24 @@ import org.mozilla.fenix.ext.components
|
|||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
@Suppress("LargeClass") // While large, most of the class is very simple
|
||||||
class DefaultToolbarMenu(
|
class DefaultToolbarMenu(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val hasAccountProblem: Boolean = false,
|
private val hasAccountProblem: Boolean = false,
|
||||||
private val requestDesktopStateProvider: () -> Boolean = { false },
|
private val requestDesktopStateProvider: () -> Boolean = { false },
|
||||||
private val onItemTapped: (ToolbarMenu.Item) -> Unit = {}
|
private val onItemTapped: (ToolbarMenu.Item) -> Unit = {},
|
||||||
|
private val lifecycleOwner: LifecycleOwner,
|
||||||
|
private val bookmarksStorage: BookmarksStorage,
|
||||||
|
readerModeStateProvider: () -> Boolean = { false },
|
||||||
|
sessionManager: SessionManager
|
||||||
) : ToolbarMenu {
|
) : ToolbarMenu {
|
||||||
|
|
||||||
|
private var currentUrlIsBookmarked = false
|
||||||
|
private var isBookmarkedJob: Job? = null
|
||||||
|
|
||||||
override val menuBuilder by lazy { BrowserMenuBuilder(menuItems, endOfMenuAlwaysVisible = true) }
|
override val menuBuilder by lazy { BrowserMenuBuilder(menuItems, endOfMenuAlwaysVisible = true) }
|
||||||
|
|
||||||
override val menuToolbar by lazy {
|
override val menuToolbar by lazy {
|
||||||
val back = BrowserMenuItemToolbar.TwoStateButton(
|
|
||||||
primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_back,
|
|
||||||
primaryContentDescription = context.getString(R.string.browser_menu_back),
|
|
||||||
primaryImageTintResource = ThemeManager.resolveAttribute(
|
|
||||||
R.attr.primaryText,
|
|
||||||
context
|
|
||||||
),
|
|
||||||
isInPrimaryState = {
|
|
||||||
context.components.core.sessionManager.selectedSession?.canGoBack ?: true
|
|
||||||
},
|
|
||||||
secondaryImageTintResource = ThemeManager.resolveAttribute(
|
|
||||||
R.attr.disabled,
|
|
||||||
context
|
|
||||||
),
|
|
||||||
disableInSecondaryState = true
|
|
||||||
) {
|
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Back)
|
|
||||||
}
|
|
||||||
|
|
||||||
val forward = BrowserMenuItemToolbar.TwoStateButton(
|
val forward = BrowserMenuItemToolbar.TwoStateButton(
|
||||||
primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_forward,
|
primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_forward,
|
||||||
primaryContentDescription = context.getString(R.string.browser_menu_forward),
|
primaryContentDescription = context.getString(R.string.browser_menu_forward),
|
||||||
@ -93,28 +89,100 @@ class DefaultToolbarMenu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserMenuItemToolbar(listOf(back, forward, refresh))
|
val share = BrowserMenuItemToolbar.Button(
|
||||||
|
imageResource = R.drawable.mozac_ic_share,
|
||||||
|
contentDescription = context.getString(R.string.browser_menu_share),
|
||||||
|
iconTintColorResource = primaryTextColor(),
|
||||||
|
listener = {
|
||||||
|
onItemTapped.invoke(ToolbarMenu.Item.Share)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
registerForIsBookmarkedUpdates(sessionManager)
|
||||||
|
val bookmark = BrowserMenuItemToolbar.TwoStateButton(
|
||||||
|
primaryImageResource = R.drawable.ic_bookmark_filled,
|
||||||
|
primaryContentDescription = context.getString(R.string.browser_menu_edit_bookmark),
|
||||||
|
primaryImageTintResource = ThemeManager.resolveAttribute(
|
||||||
|
R.attr.primaryText,
|
||||||
|
context
|
||||||
|
),
|
||||||
|
// TwoStateButton.isInPrimaryState must be synchronous, and checking bookmark state is
|
||||||
|
// relatively slow. The best we can do here is periodically compute and cache a new "is
|
||||||
|
// bookmarked" state, and use that whenever the menu has been opened.
|
||||||
|
isInPrimaryState = { currentUrlIsBookmarked },
|
||||||
|
secondaryImageResource = R.drawable.ic_bookmark_outline,
|
||||||
|
secondaryContentDescription = context.getString(R.string.browser_menu_bookmark),
|
||||||
|
secondaryImageTintResource = ThemeManager.resolveAttribute(
|
||||||
|
R.attr.primaryText,
|
||||||
|
context
|
||||||
|
),
|
||||||
|
disableInSecondaryState = false
|
||||||
|
) {
|
||||||
|
if (!currentUrlIsBookmarked) currentUrlIsBookmarked = true
|
||||||
|
onItemTapped.invoke(ToolbarMenu.Item.Bookmark)
|
||||||
|
}
|
||||||
|
|
||||||
|
BrowserMenuItemToolbar(listOf(forward, bookmark, share, refresh))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val menuItems by lazy {
|
private val menuItems by lazy {
|
||||||
val items = mutableListOf(
|
// Predicates that are called once, during screen init
|
||||||
BrowserMenuImageText(
|
val shouldShowSaveToCollection = (context.asActivity() as? HomeActivity)
|
||||||
|
?.browsingModeManager?.mode == BrowsingMode.Normal
|
||||||
|
val shouldDeleteDataOnQuit = Settings.getInstance(context)
|
||||||
|
.shouldDeleteBrowsingDataOnQuit
|
||||||
|
|
||||||
|
// Predicates that need to be repeatedly called as the session changes
|
||||||
|
fun shouldShowAddToHomescreen(): Boolean {
|
||||||
|
return context.components.useCases.webAppUseCases.isPinningSupported() &&
|
||||||
|
context.components.core.sessionManager.selectedSession != null
|
||||||
|
}
|
||||||
|
fun shouldShowReaderMode(): Boolean = sessionManager.selectedSession?.readerable ?: false
|
||||||
|
fun shouldShowOpenInApp(): Boolean = sessionManager.selectedSession?.let { session ->
|
||||||
|
val appLink =
|
||||||
|
context.components.useCases.appLinksUseCases.appLinkRedirect
|
||||||
|
appLink(session.url).hasExternalApp()
|
||||||
|
} ?: false
|
||||||
|
fun shouldShowReaderAppearance(): Boolean =
|
||||||
|
sessionManager.selectedSession?.readerMode ?: false
|
||||||
|
|
||||||
|
listOfNotNull(
|
||||||
|
help,
|
||||||
|
settings,
|
||||||
|
library,
|
||||||
|
desktopMode,
|
||||||
|
addToHomescreen.apply { visible = ::shouldShowAddToHomescreen },
|
||||||
|
findInPage,
|
||||||
|
privateTab,
|
||||||
|
newTab,
|
||||||
|
reportIssue,
|
||||||
|
if (shouldShowSaveToCollection) saveToCollection else null,
|
||||||
|
if (shouldDeleteDataOnQuit) deleteDataOnQuit else null,
|
||||||
|
readerMode.apply { visible = ::shouldShowReaderMode },
|
||||||
|
readerAppearance.apply { visible = ::shouldShowReaderAppearance },
|
||||||
|
openInApp.apply { visible = ::shouldShowOpenInApp },
|
||||||
|
BrowserMenuDivider(),
|
||||||
|
menuToolbar
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val help = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_help),
|
context.getString(R.string.browser_menu_help),
|
||||||
R.drawable.ic_help,
|
R.drawable.ic_help,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Help)
|
onItemTapped.invoke(ToolbarMenu.Item.Help)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuHighlightableItem(
|
private val settings = BrowserMenuHighlightableItem(
|
||||||
label = context.getString(R.string.browser_menu_settings),
|
label = context.getString(R.string.browser_menu_settings),
|
||||||
imageResource = R.drawable.ic_settings,
|
imageResource = R.drawable.ic_settings,
|
||||||
iconTintColorResource = if (hasAccountProblem)
|
iconTintColorResource = if (hasAccountProblem)
|
||||||
R.color.sync_error_text_color else
|
R.color.sync_error_text_color else
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context),
|
primaryTextColor(),
|
||||||
textColorResource = if (hasAccountProblem)
|
textColorResource = if (hasAccountProblem)
|
||||||
R.color.sync_error_text_color else
|
R.color.sync_error_text_color else
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context),
|
primaryTextColor(),
|
||||||
highlight = if (hasAccountProblem) {
|
highlight = if (hasAccountProblem) {
|
||||||
BrowserMenuHighlightableItem.Highlight(
|
BrowserMenuHighlightableItem.Highlight(
|
||||||
endImageResource = R.drawable.ic_alert,
|
endImageResource = R.drawable.ic_alert,
|
||||||
@ -124,112 +192,124 @@ class DefaultToolbarMenu(
|
|||||||
} else null
|
} else null
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Settings)
|
onItemTapped.invoke(ToolbarMenu.Item.Settings)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val library = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_your_library),
|
label = context.getString(R.string.browser_menu_your_library),
|
||||||
R.drawable.ic_library,
|
imageResource = R.drawable.ic_library,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Library)
|
onItemTapped.invoke(ToolbarMenu.Item.Library)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuImageSwitch(
|
private val desktopMode = BrowserMenuImageSwitch(
|
||||||
R.drawable.ic_desktop,
|
imageResource = R.drawable.ic_desktop,
|
||||||
context.getString(R.string.browser_menu_desktop_site),
|
label = context.getString(R.string.browser_menu_desktop_site),
|
||||||
requestDesktopStateProvider
|
initialState = requestDesktopStateProvider
|
||||||
) { checked ->
|
) { checked ->
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
|
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val addToHomescreen = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_add_to_homescreen),
|
label = context.getString(R.string.browser_menu_add_to_homescreen),
|
||||||
R.drawable.ic_add_to_homescreen,
|
imageResource = R.drawable.ic_add_to_homescreen,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
|
onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
|
||||||
}.apply {
|
}
|
||||||
visible = ::shouldShowAddToHomescreen
|
|
||||||
},
|
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val findInPage = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_find_in_page),
|
label = context.getString(R.string.browser_menu_find_in_page),
|
||||||
R.drawable.mozac_ic_search,
|
imageResource = R.drawable.mozac_ic_search,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
|
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val privateTab = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_private_tab),
|
label = context.getString(R.string.browser_menu_private_tab),
|
||||||
R.drawable.ic_private_browsing,
|
imageResource = R.drawable.ic_private_browsing,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.NewPrivateTab)
|
onItemTapped.invoke(ToolbarMenu.Item.NewPrivateTab)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val newTab = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_new_tab),
|
label = context.getString(R.string.browser_menu_new_tab),
|
||||||
R.drawable.ic_new,
|
imageResource = R.drawable.ic_new,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.NewTab)
|
onItemTapped.invoke(ToolbarMenu.Item.NewTab)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val reportIssue = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_share),
|
label = context.getString(R.string.browser_menu_report_issue),
|
||||||
R.drawable.mozac_ic_share,
|
imageResource = R.drawable.ic_report_issues,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Share)
|
|
||||||
},
|
|
||||||
|
|
||||||
BrowserMenuImageText(
|
|
||||||
context.getString(R.string.browser_menu_report_issue),
|
|
||||||
R.drawable.ic_report_issues,
|
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.ReportIssue)
|
onItemTapped.invoke(ToolbarMenu.Item.ReportIssue)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
if ((context.asActivity() as? HomeActivity)?.browsingModeManager?.mode == BrowsingMode.Normal) {
|
private val saveToCollection = BrowserMenuImageText(
|
||||||
items.add(
|
label = context.getString(R.string.browser_menu_save_to_collection),
|
||||||
BrowserMenuImageText(
|
imageResource = R.drawable.ic_tab_collection,
|
||||||
context.getString(R.string.browser_menu_save_to_collection),
|
iconTintColorResource = primaryTextColor()
|
||||||
R.drawable.ic_tab_collection,
|
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
|
onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Settings.getInstance(context).shouldDeleteBrowsingDataOnQuit) {
|
private val deleteDataOnQuit = BrowserMenuImageText(
|
||||||
items.add(
|
label = context.getString(R.string.delete_browsing_data_on_quit_action),
|
||||||
BrowserMenuImageText(
|
imageResource = R.drawable.ic_exit,
|
||||||
context.getString(R.string.delete_browsing_data_on_quit_action),
|
iconTintColorResource = primaryTextColor()
|
||||||
R.drawable.ic_exit,
|
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Quit)
|
onItemTapped.invoke(ToolbarMenu.Item.Quit)
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
private val readerMode = BrowserMenuImageSwitch(
|
||||||
|
label = context.getString(R.string.browser_menu_read),
|
||||||
|
imageResource = R.drawable.ic_readermode,
|
||||||
|
initialState = readerModeStateProvider
|
||||||
|
) { checked ->
|
||||||
|
onItemTapped.invoke(ToolbarMenu.Item.ReaderMode(checked))
|
||||||
}
|
}
|
||||||
|
|
||||||
items.add(
|
private val readerAppearance = BrowserMenuImageText(
|
||||||
BrowserMenuDivider()
|
label = context.getString(R.string.browser_menu_read_appearance),
|
||||||
)
|
imageResource = R.drawable.ic_readermode_appearance,
|
||||||
|
iconTintColorResource = primaryTextColor()
|
||||||
items.add(
|
) {
|
||||||
menuToolbar
|
onItemTapped.invoke(ToolbarMenu.Item.ReaderModeAppearance)
|
||||||
)
|
|
||||||
|
|
||||||
items
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldShowAddToHomescreen(): Boolean {
|
private val openInApp = BrowserMenuImageText(
|
||||||
return context.components.useCases.webAppUseCases.isPinningSupported() &&
|
label = context.getString(R.string.browser_menu_open_app_link),
|
||||||
context.components.core.sessionManager.selectedSession != null
|
imageResource = R.drawable.ic_app_links,
|
||||||
|
iconTintColorResource = primaryTextColor()
|
||||||
|
) {
|
||||||
|
onItemTapped.invoke(ToolbarMenu.Item.OpenInApp)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
||||||
|
|
||||||
|
private fun registerForIsBookmarkedUpdates(sessionManager: SessionManager) {
|
||||||
|
val observer = object : Session.Observer {
|
||||||
|
override fun onUrlChanged(session: Session, url: String) {
|
||||||
|
currentUrlIsBookmarked = false
|
||||||
|
updateCurrentUrlIsBookmarked(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionManager.selectedSession?.url?.let { updateCurrentUrlIsBookmarked(it) }
|
||||||
|
sessionManager.selectedSession?.register(observer, lifecycleOwner)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCurrentUrlIsBookmarked(newUrl: String) {
|
||||||
|
isBookmarkedJob?.cancel()
|
||||||
|
isBookmarkedJob = lifecycleOwner.lifecycleScope.launch {
|
||||||
|
currentUrlIsBookmarked = bookmarksStorage
|
||||||
|
.getBookmarksWithUrl(newUrl)
|
||||||
|
.any { it.url == newUrl }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ interface ToolbarMenu {
|
|||||||
object SaveToCollection : Item()
|
object SaveToCollection : Item()
|
||||||
object AddToHomeScreen : Item()
|
object AddToHomeScreen : Item()
|
||||||
object Quit : Item()
|
object Quit : Item()
|
||||||
|
data class ReaderMode(val isChecked: Boolean) : Item()
|
||||||
|
object OpenInApp : Item()
|
||||||
|
object Bookmark : Item()
|
||||||
|
object ReaderModeAppearance : Item()
|
||||||
}
|
}
|
||||||
|
|
||||||
val menuBuilder: BrowserMenuBuilder
|
val menuBuilder: BrowserMenuBuilder
|
||||||
|
@ -99,60 +99,58 @@ class CustomTabToolbarMenu(
|
|||||||
private val menuItems by lazy {
|
private val menuItems by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
menuToolbar,
|
menuToolbar,
|
||||||
|
|
||||||
BrowserMenuDivider(),
|
BrowserMenuDivider(),
|
||||||
|
share,
|
||||||
BrowserMenuImageText(
|
desktopMode,
|
||||||
context.getString(R.string.browser_menu_share),
|
findInPage,
|
||||||
R.drawable.mozac_ic_share,
|
openInFenix,
|
||||||
textColorResource = ThemeManager.resolveAttribute(
|
BrowserMenuDivider(),
|
||||||
R.attr.primaryText,
|
poweredBy
|
||||||
context
|
|
||||||
),
|
|
||||||
iconTintColorResource = ThemeManager.resolveAttribute(
|
|
||||||
R.attr.primaryText,
|
|
||||||
context
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val share = BrowserMenuImageText(
|
||||||
|
label = context.getString(R.string.browser_menu_share),
|
||||||
|
imageResource = R.drawable.mozac_ic_share,
|
||||||
|
textColorResource = primaryTextColor(),
|
||||||
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.Share)
|
onItemTapped.invoke(ToolbarMenu.Item.Share)
|
||||||
},
|
}
|
||||||
|
|
||||||
BrowserMenuSwitch(context.getString(R.string.browser_menu_desktop_site),
|
private val desktopMode = BrowserMenuSwitch(
|
||||||
{ session?.desktopMode ?: false }, { checked ->
|
label = context.getString(R.string.browser_menu_desktop_site),
|
||||||
|
initialState = { session?.desktopMode ?: false }, listener = { checked ->
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
|
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
|
||||||
}),
|
})
|
||||||
|
|
||||||
BrowserMenuImageText(
|
private val findInPage = BrowserMenuImageText(
|
||||||
context.getString(R.string.browser_menu_find_in_page),
|
label = context.getString(R.string.browser_menu_find_in_page),
|
||||||
R.drawable.mozac_ic_search,
|
imageResource = R.drawable.mozac_ic_search,
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
iconTintColorResource = primaryTextColor()
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
|
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
|
||||||
},
|
}
|
||||||
|
|
||||||
SimpleBrowserMenuItem(
|
private val openInFenix = SimpleBrowserMenuItem(
|
||||||
{
|
label = {
|
||||||
val appName = context.getString(R.string.app_name)
|
val appName = context.getString(R.string.app_name)
|
||||||
context.getString(R.string.browser_menu_open_in_fenix, appName)
|
context.getString(R.string.browser_menu_open_in_fenix, appName)
|
||||||
}(),
|
}(),
|
||||||
textColorResource = ThemeManager.resolveAttribute(
|
textSize = ToolbarMenu.CAPTION_TEXT_SIZE,
|
||||||
R.attr.primaryText,
|
textColorResource = primaryTextColor()
|
||||||
context
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(ToolbarMenu.Item.OpenInFenix)
|
onItemTapped.invoke(ToolbarMenu.Item.OpenInFenix)
|
||||||
},
|
|
||||||
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
|
|
||||||
SimpleBrowserMenuItem(
|
|
||||||
{
|
|
||||||
val appName = context.getString(R.string.app_name)
|
|
||||||
context.getString(R.string.browser_menu_powered_by2, appName).toUpperCase()
|
|
||||||
}(),
|
|
||||||
ToolbarMenu.CAPTION_TEXT_SIZE,
|
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val poweredBy = SimpleBrowserMenuItem(
|
||||||
|
label = {
|
||||||
|
val appName = context.getString(R.string.app_name)
|
||||||
|
context.getString(R.string.browser_menu_powered_by, appName).toUpperCase()
|
||||||
|
}(),
|
||||||
|
textSize = ToolbarMenu.CAPTION_TEXT_SIZE,
|
||||||
|
textColorResource = primaryTextColor()
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import android.view.Gravity
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import com.airbnb.lottie.LottieCompositionFactory
|
import com.airbnb.lottie.LottieCompositionFactory
|
||||||
import com.airbnb.lottie.LottieDrawable
|
import com.airbnb.lottie.LottieDrawable
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
@ -28,7 +27,6 @@ class CustomTabsIntegration(
|
|||||||
toolbar: BrowserToolbar,
|
toolbar: BrowserToolbar,
|
||||||
sessionId: String,
|
sessionId: String,
|
||||||
activity: Activity,
|
activity: Activity,
|
||||||
quickActionbar: NestedScrollView,
|
|
||||||
engineLayout: View,
|
engineLayout: View,
|
||||||
onItemTapped: (ToolbarMenu.Item) -> Unit = {}
|
onItemTapped: (ToolbarMenu.Item) -> Unit = {}
|
||||||
) : LifecycleAwareFeature, BackHandler {
|
) : LifecycleAwareFeature, BackHandler {
|
||||||
@ -52,9 +50,6 @@ class CustomTabsIntegration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide the Quick Action Bar.
|
|
||||||
quickActionbar.visibility = View.GONE
|
|
||||||
|
|
||||||
val task = LottieCompositionFactory
|
val task = LottieCompositionFactory
|
||||||
.fromRawRes(
|
.fromRawRes(
|
||||||
activity,
|
activity,
|
||||||
|
@ -32,8 +32,6 @@ import org.mozilla.fenix.R
|
|||||||
import org.mozilla.fenix.browser.BaseBrowserFragment
|
import org.mozilla.fenix.browser.BaseBrowserFragment
|
||||||
import org.mozilla.fenix.browser.CustomTabContextMenuCandidate
|
import org.mozilla.fenix.browser.CustomTabContextMenuCandidate
|
||||||
import org.mozilla.fenix.browser.FenixSnackbarDelegate
|
import org.mozilla.fenix.browser.FenixSnackbarDelegate
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarController
|
|
||||||
import org.mozilla.fenix.components.toolbar.BrowserToolbarInteractor
|
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
@ -63,12 +61,11 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
customTabSessionId?.let { customTabSessionId ->
|
customTabSessionId?.let { customTabSessionId ->
|
||||||
customTabsIntegration.set(
|
customTabsIntegration.set(
|
||||||
feature = CustomTabsIntegration(
|
feature = CustomTabsIntegration(
|
||||||
requireComponents.core.sessionManager,
|
sessionManager = requireComponents.core.sessionManager,
|
||||||
toolbar,
|
toolbar = toolbar,
|
||||||
customTabSessionId,
|
sessionId = customTabSessionId,
|
||||||
activity,
|
activity = activity,
|
||||||
view.nestedScrollQuickAction,
|
engineLayout = view.swipeRefresh,
|
||||||
view.swipeRefresh,
|
|
||||||
onItemTapped = { browserInteractor.onBrowserToolbarMenuItemTapped(it) }
|
onItemTapped = { browserInteractor.onBrowserToolbarMenuItemTapped(it) }
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
@ -123,7 +120,7 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeFrom(browserStore) {
|
consumeFrom(browserFragmentStore) {
|
||||||
browserToolbarView.update(it)
|
browserToolbarView.update(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,11 +143,6 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler {
|
|||||||
return customTabsIntegration.onBackPressed() || super.removeSessionIfNeeded()
|
return customTabsIntegration.onBackPressed() || super.removeSessionIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBrowserToolbarViewInteractor(
|
|
||||||
browserToolbarController: BrowserToolbarController,
|
|
||||||
session: Session?
|
|
||||||
) = BrowserToolbarInteractor(browserToolbarController)
|
|
||||||
|
|
||||||
override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) {
|
override fun navToQuickSettingsSheet(session: Session, sitePermissions: SitePermissions?) {
|
||||||
val directions = ExternalAppBrowserFragmentDirections
|
val directions = ExternalAppBrowserFragmentDirections
|
||||||
.actionExternalAppBrowserFragmentToQuickSettingsSheetDialogFragment(
|
.actionExternalAppBrowserFragmentToQuickSettingsSheetDialogFragment(
|
||||||
|
@ -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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -132,9 +132,6 @@ class Settings private constructor(
|
|||||||
get() = trackingProtectionOnboardingCount < trackingProtectionOnboardingMaximumCount &&
|
get() = trackingProtectionOnboardingCount < trackingProtectionOnboardingMaximumCount &&
|
||||||
!trackingProtectionOnboardingShownThisSession
|
!trackingProtectionOnboardingShownThisSession
|
||||||
|
|
||||||
val shouldAutoBounceQuickActionSheet: Boolean
|
|
||||||
get() = autoBounceQuickActionSheetCount < autoBounceMaximumCount
|
|
||||||
|
|
||||||
val shouldShowSecurityPinWarningSync: Boolean
|
val shouldShowSecurityPinWarningSync: Boolean
|
||||||
get() = loginsSecureWarningSyncCount < showLoginsSecureWarningSyncMaxCount
|
get() = loginsSecureWarningSyncCount < showLoginsSecureWarningSyncMaxCount
|
||||||
|
|
||||||
@ -225,12 +222,6 @@ class Settings private constructor(
|
|||||||
else -> appContext.getString(R.string.preference_light_theme)
|
else -> appContext.getString(R.string.preference_light_theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = PRIVATE)
|
|
||||||
internal val autoBounceQuickActionSheetCount by intPreference(
|
|
||||||
appContext.getPreferenceKey(R.string.pref_key_bounce_quick_action),
|
|
||||||
default = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = PRIVATE)
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
internal val loginsSecureWarningSyncCount by intPreference(
|
internal val loginsSecureWarningSyncCount by intPreference(
|
||||||
appContext.getPreferenceKey(R.string.pref_key_logins_secure_warning_sync),
|
appContext.getPreferenceKey(R.string.pref_key_logins_secure_warning_sync),
|
||||||
@ -257,13 +248,6 @@ class Settings private constructor(
|
|||||||
).apply()
|
).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun incrementAutomaticBounceQuickActionSheetCount() {
|
|
||||||
preferences.edit().putInt(
|
|
||||||
appContext.getPreferenceKey(R.string.pref_key_bounce_quick_action),
|
|
||||||
autoBounceQuickActionSheetCount + 1
|
|
||||||
).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
val shouldShowSearchSuggestions by booleanPreference(
|
val shouldShowSearchSuggestions by booleanPreference(
|
||||||
appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions),
|
appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions),
|
||||||
default = true
|
default = true
|
||||||
|
14
app/src/main/res/drawable/ic_app_links.xml
Normal file
14
app/src/main/res/drawable/ic_app_links.xml
Normal file
@ -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>
|
14
app/src/main/res/drawable/ic_readermode_appearance.xml
Normal file
14
app/src/main/res/drawable/ic_readermode_appearance.xml
Normal file
@ -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" />
|
|
@ -14,7 +14,7 @@
|
|||||||
android:id="@+id/swipeRefresh"
|
android:id="@+id/swipeRefresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="@dimen/toolbar_and_qab_height">
|
android:layout_marginBottom="@dimen/browser_toolbar_height">
|
||||||
|
|
||||||
<mozilla.components.concept.engine.EngineView
|
<mozilla.components.concept.engine.EngineView
|
||||||
android:id="@+id/engineView"
|
android:id="@+id/engineView"
|
||||||
@ -22,14 +22,6 @@
|
|||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:id="@+id/nestedScrollQuickAction"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:mozac_behavior_hideable="true"
|
|
||||||
app:mozac_behavior_peekHeight="12dp"
|
|
||||||
app:layout_behavior="org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior" />
|
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
android:id="@+id/stubFindInPage"
|
android:id="@+id/stubFindInPage"
|
||||||
android:inflatedId="@+id/findInPageView"
|
android:inflatedId="@+id/findInPageView"
|
||||||
|
@ -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>
|
|
@ -67,55 +67,4 @@
|
|||||||
<attr name="onboardingKey" format="reference" />
|
<attr name="onboardingKey" format="reference" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="QuickActionSheetBehavior_Layout">
|
|
||||||
<!-- The height of the bottom sheet when it is collapsed. -->
|
|
||||||
<attr format="dimension" name="mozac_behavior_peekHeight">
|
|
||||||
<!-- Peek at the 16:9 ratio keyline of its parent -->
|
|
||||||
<enum name="auto" value="-1"/>
|
|
||||||
</attr>
|
|
||||||
<!-- Whether this bottom sheet can be hidden by dragging it further downwards -->
|
|
||||||
<attr format="boolean" name="mozac_behavior_hideable"/>
|
|
||||||
<!-- Skip the collapsed state once expanded; no effect unless it is hideable -->
|
|
||||||
<attr format="boolean" name="mozac_behavior_skipCollapsed"/>
|
|
||||||
<!-- Whether height of expanded sheet wraps content or not -->
|
|
||||||
<attr format="boolean" name="mozac_behavior_fitToContents"/>
|
|
||||||
<!-- The ratio to be used to set the height of half-expanded state in proportion to parent, when
|
|
||||||
fitToContents is false. Defaults to true half, 0.5, if not explicitly set. Ratio must be a
|
|
||||||
float value between 0 and 1 and produce a half-expanded state height larger than the
|
|
||||||
peek height for the half-expanded state to be operational -->
|
|
||||||
<attr format="reference|float" name="mozac_behavior_halfExpandedRatio"/>
|
|
||||||
<!-- The top offset of the BottomSheet in the expanded-state when fitsToContent is false.
|
|
||||||
The default value is 0, which results in the sheet matching the parent's top. -->
|
|
||||||
<attr format="reference|integer" name="mozac_behavior_expandedOffset"/>
|
|
||||||
<!-- Shape appearance style reference for BottomSheet. Attribute declaration is in the shape
|
|
||||||
package. -->
|
|
||||||
<attr name="shapeAppearance"/>
|
|
||||||
<!-- Shape appearance overlay style reference for BottomSheet. To be used to augment attributes
|
|
||||||
declared in the shapeAppearance. Attribute declaration is in the shape package. -->
|
|
||||||
<attr name="shapeAppearanceOverlay"/>
|
|
||||||
<!-- Background color used by the BottomSheetBehavior background drawable when shape theming is
|
|
||||||
enabled. Accepts a ColorStateList or ColorInt. If shape theming is not enabled,
|
|
||||||
android:background should instead be utilized to set the background resource. -->
|
|
||||||
<attr name="backgroundTint"/>
|
|
||||||
<!-- Behavior properties will be saved and restored by evaluating each flag.
|
|
||||||
usage: app:behavior_saveFlags=”hideable|skipCollapsed” -->
|
|
||||||
<attr name="mozac_behavior_saveFlags">
|
|
||||||
<!-- This flag will preserve the peekHeight on configuration change. -->
|
|
||||||
<flag name="peekHeight" value="0x1"/>
|
|
||||||
<!-- This flag will preserve the fitToContents boolean value on configuration change. -->
|
|
||||||
<flag name="fitToContents" value="0x2"/>
|
|
||||||
<!-- This flag will preserve the hideable boolean value on configuration change. -->
|
|
||||||
<flag name="hideable" value="0x4"/>
|
|
||||||
<!-- This flag will preserve the skipCollapsed boolean value on configuration change. -->
|
|
||||||
<flag name="skipCollapsed" value="0x8"/>
|
|
||||||
<!-- This flag will preserve the all the aforementioned values on configuration change. -->
|
|
||||||
<flag name="all" value="-1"/>
|
|
||||||
<!-- This flag will not preserve the aforementioned values on configuration change. The only
|
|
||||||
value preserved will be the positional state, e.g. collapsed, hidden, expanded, etc.
|
|
||||||
This is the default behavior. -->
|
|
||||||
<flag name="none" value="0"/>
|
|
||||||
</attr>
|
|
||||||
<attr name="android:elevation"/>
|
|
||||||
|
|
||||||
</declare-styleable>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -54,7 +54,6 @@
|
|||||||
|
|
||||||
<!-- Browser Toolbar -->
|
<!-- Browser Toolbar -->
|
||||||
<dimen name="browser_toolbar_height">56dp</dimen>
|
<dimen name="browser_toolbar_height">56dp</dimen>
|
||||||
<dimen name="toolbar_and_qab_height">67dp</dimen>
|
|
||||||
|
|
||||||
<!-- SignIn Component -->
|
<!-- SignIn Component -->
|
||||||
<dimen name="sign_in_button_padding">10dp</dimen>
|
<dimen name="sign_in_button_padding">10dp</dimen>
|
||||||
|
@ -59,6 +59,10 @@
|
|||||||
<string name="browser_menu_refresh">Refresh</string>
|
<string name="browser_menu_refresh">Refresh</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): Stop loading current website -->
|
<!-- Content description (not visible, for screen readers etc.): Stop loading current website -->
|
||||||
<string name="browser_menu_stop">Stop</string>
|
<string name="browser_menu_stop">Stop</string>
|
||||||
|
<!-- Content description (not visible, for screen readers etc.): Bookmark the current page -->
|
||||||
|
<string name="browser_menu_bookmark">Bookmark</string>
|
||||||
|
<!-- Content description (not visible, for screen readers etc.): Un-bookmark the current page -->
|
||||||
|
<string name="browser_menu_edit_bookmark">Edit bookmark</string>
|
||||||
<!-- Browser menu button that sends a user to help articles -->
|
<!-- Browser menu button that sends a user to help articles -->
|
||||||
<string name="browser_menu_help">Help</string>
|
<string name="browser_menu_help">Help</string>
|
||||||
<!-- Browser menu button that sends a to a the what's new article -->
|
<!-- Browser menu button that sends a to a the what's new article -->
|
||||||
@ -94,6 +98,12 @@
|
|||||||
<!-- Browser menu text shown in custom tabs to indicate this is a Fenix tab
|
<!-- Browser menu text shown in custom tabs to indicate this is a Fenix tab
|
||||||
The first parameter is the name of the app defined in app_name (for example: Fenix) -->
|
The first parameter is the name of the app defined in app_name (for example: Fenix) -->
|
||||||
<string name="browser_menu_powered_by2">Powered by %1$s</string>
|
<string name="browser_menu_powered_by2">Powered by %1$s</string>
|
||||||
|
<!-- Browser menu button to put the the current page in reader mode -->
|
||||||
|
<string name="browser_menu_read">Reader view</string>
|
||||||
|
<!-- Browser menu button to open the current page in an external app -->
|
||||||
|
<string name="browser_menu_open_app_link">Open in App</string>
|
||||||
|
<!-- Browser menu button to configure reader mode appearance e.g. the used font type and size -->
|
||||||
|
<string name="browser_menu_read_appearance">Appearance</string>
|
||||||
|
|
||||||
<!-- Search Fragment -->
|
<!-- Search Fragment -->
|
||||||
<!-- Button in the search view that lets a user search by scanning a QR code -->
|
<!-- Button in the search view that lets a user search by scanning a QR code -->
|
||||||
@ -302,27 +312,6 @@
|
|||||||
<!-- Preference for using following device theme -->
|
<!-- Preference for using following device theme -->
|
||||||
<string name="preference_follow_device_theme">Follow device theme</string>
|
<string name="preference_follow_device_theme">Follow device theme</string>
|
||||||
|
|
||||||
<!-- Quick Action Sheet -->
|
|
||||||
<!-- Button in the browser chrome to share the current page -->
|
|
||||||
<string name="quick_action_share">Share</string>
|
|
||||||
<!-- Button in the browser chrome to download the current page -->
|
|
||||||
<string name="quick_action_download">Download</string>
|
|
||||||
<!-- Button in the browser chrome in the browser to bookmark the current page -->
|
|
||||||
<string name="quick_action_bookmark">Bookmark</string>
|
|
||||||
<!-- Button in the browser chrome in the browser to edit the bookmark of the current page -->
|
|
||||||
<string name="quick_action_bookmark_edit">Edit Bookmark</string>
|
|
||||||
<!-- Button in the browser chrome in the browser to put the the current page in reader mode -->
|
|
||||||
<string name="quick_action_read">Read</string>
|
|
||||||
<!-- Button in the browser chrome to exit reader mode -->
|
|
||||||
<string name="quick_action_read_close">Close</string>
|
|
||||||
<!-- Button in the browser chrome to open the current page in an external app -->
|
|
||||||
<string name="quick_action_open_app_link">Open in App</string>
|
|
||||||
<!-- Button in the browser chrome to configure reader mode appearance e.g. the used font type and size -->
|
|
||||||
<string name="quick_action_read_appearance">Appearance</string>
|
|
||||||
<!-- Content description (not visible, for screen readers etc.): Quick action sheet handle to provide users
|
|
||||||
with shortcuts to commonly used actions such as Share, Bookmark etc.. -->
|
|
||||||
<string name="quick_action_sheet_handle">Quick actions</string>
|
|
||||||
|
|
||||||
<!-- Library -->
|
<!-- Library -->
|
||||||
<!-- Option in Library to open Sessions page -->
|
<!-- Option in Library to open Sessions page -->
|
||||||
<string name="library_sessions">Sessions</string>
|
<string name="library_sessions">Sessions</string>
|
||||||
|
@ -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,52 +1,21 @@
|
|||||||
package org.mozilla.fenix.components.toolbar
|
package org.mozilla.fenix.components.toolbar
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import io.mockk.Runs
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.just
|
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.mozilla.fenix.browser.readermode.ReaderModeController
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetController
|
|
||||||
|
|
||||||
class BrowserInteractorTest {
|
class BrowserInteractorTest {
|
||||||
|
|
||||||
lateinit var metrics: MetricController
|
|
||||||
lateinit var context: Context
|
|
||||||
lateinit var browserStore: BrowserFragmentStore
|
|
||||||
lateinit var browserToolbarController: BrowserToolbarController
|
lateinit var browserToolbarController: BrowserToolbarController
|
||||||
lateinit var quickActionSheetController: QuickActionSheetController
|
|
||||||
lateinit var readerModeController: ReaderModeController
|
|
||||||
lateinit var session: Session
|
|
||||||
lateinit var interactor: BrowserInteractor
|
lateinit var interactor: BrowserInteractor
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
metrics = mockk()
|
|
||||||
context = mockk()
|
|
||||||
browserStore = mockk(relaxed = true)
|
|
||||||
browserToolbarController = mockk(relaxed = true)
|
browserToolbarController = mockk(relaxed = true)
|
||||||
quickActionSheetController = mockk(relaxed = true)
|
|
||||||
readerModeController = mockk(relaxed = true)
|
|
||||||
session = mockk()
|
|
||||||
interactor = BrowserInteractor(
|
interactor = BrowserInteractor(
|
||||||
context,
|
browserToolbarController
|
||||||
browserStore,
|
|
||||||
browserToolbarController,
|
|
||||||
quickActionSheetController,
|
|
||||||
readerModeController,
|
|
||||||
session
|
|
||||||
)
|
)
|
||||||
every { context.metrics } returns metrics
|
|
||||||
every { context.components.core.sessionManager.selectedSession } returns session
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -85,86 +54,4 @@ class BrowserInteractorTest {
|
|||||||
|
|
||||||
verify { browserToolbarController.handleToolbarItemInteraction(item) }
|
verify { browserToolbarController.handleToolbarItemInteraction(item) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetOpened() {
|
|
||||||
every { metrics.track(Event.QuickActionSheetOpened) } just Runs
|
|
||||||
|
|
||||||
interactor.onQuickActionSheetOpened()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetOpened) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetClosed() {
|
|
||||||
every { metrics.track(Event.QuickActionSheetClosed) } just Runs
|
|
||||||
|
|
||||||
interactor.onQuickActionSheetClosed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetClosed) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetSharePressed() {
|
|
||||||
interactor.onQuickActionSheetSharePressed()
|
|
||||||
|
|
||||||
verify { quickActionSheetController.handleShare() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetDownloadPressed() {
|
|
||||||
every { metrics.track(Event.QuickActionSheetDownloadTapped) } just Runs
|
|
||||||
|
|
||||||
interactor.onQuickActionSheetDownloadPressed()
|
|
||||||
|
|
||||||
verify { quickActionSheetController.handleDownload() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetBookmarkPressed() {
|
|
||||||
interactor.onQuickActionSheetBookmarkPressed()
|
|
||||||
|
|
||||||
verify { quickActionSheetController.handleBookmark() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetReadPressed() {
|
|
||||||
every { session.readerMode } returns false
|
|
||||||
every { metrics.track(Event.QuickActionSheetOpened) } just Runs
|
|
||||||
|
|
||||||
interactor.onQuickActionSheetReadPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetOpened) }
|
|
||||||
verify { readerModeController.showReaderView() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetReadPressedWithActiveReaderMode() {
|
|
||||||
every { session.readerMode } returns true
|
|
||||||
every { metrics.track(Event.QuickActionSheetClosed) } just Runs
|
|
||||||
|
|
||||||
interactor.onQuickActionSheetReadPressed()
|
|
||||||
|
|
||||||
verify { metrics.track(Event.QuickActionSheetClosed) }
|
|
||||||
verify { readerModeController.hideReaderView() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetOpenLinkPressed() {
|
|
||||||
interactor.onQuickActionSheetOpenLinkPressed()
|
|
||||||
|
|
||||||
verify { quickActionSheetController.handleOpenLink() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onQuickActionSheetAppearancePressed() {
|
|
||||||
every { metrics.track(Event.ReaderModeAppearanceOpened) } just Runs
|
|
||||||
|
|
||||||
interactor.onQuickActionSheetAppearancePressed()
|
|
||||||
|
|
||||||
verify {
|
|
||||||
metrics.track(Event.ReaderModeAppearanceOpened)
|
|
||||||
readerModeController.showControls()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ package org.mozilla.fenix.components.toolbar
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
@ -52,7 +51,6 @@ import org.mozilla.fenix.ext.nav
|
|||||||
import org.mozilla.fenix.ext.toTab
|
import org.mozilla.fenix.ext.toTab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionSheetBehavior
|
|
||||||
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
|
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
@ -72,8 +70,6 @@ class DefaultBrowserToolbarControllerTest {
|
|||||||
private val getSupportUrl: () -> String = { "https://supportUrl.org" }
|
private val getSupportUrl: () -> String = { "https://supportUrl.org" }
|
||||||
private val openInFenixIntent: Intent = mockk(relaxed = true)
|
private val openInFenixIntent: Intent = mockk(relaxed = true)
|
||||||
private val currentSessionAsTab: Tab = mockk(relaxed = true)
|
private val currentSessionAsTab: Tab = mockk(relaxed = true)
|
||||||
private val bottomSheetBehavior: QuickActionSheetBehavior<NestedScrollView> =
|
|
||||||
mockk(relaxed = true)
|
|
||||||
private val metrics: MetricController = mockk(relaxed = true)
|
private val metrics: MetricController = mockk(relaxed = true)
|
||||||
private val searchUseCases: SearchUseCases = mockk(relaxed = true)
|
private val searchUseCases: SearchUseCases = mockk(relaxed = true)
|
||||||
private val sessionUseCases: SessionUseCases = mockk(relaxed = true)
|
private val sessionUseCases: SessionUseCases = mockk(relaxed = true)
|
||||||
@ -99,11 +95,14 @@ class DefaultBrowserToolbarControllerTest {
|
|||||||
customTabSession = null,
|
customTabSession = null,
|
||||||
getSupportUrl = getSupportUrl,
|
getSupportUrl = getSupportUrl,
|
||||||
openInFenixIntent = openInFenixIntent,
|
openInFenixIntent = openInFenixIntent,
|
||||||
bottomSheetBehavior = bottomSheetBehavior,
|
|
||||||
scope = scope,
|
scope = scope,
|
||||||
browserLayout = browserLayout,
|
browserLayout = browserLayout,
|
||||||
swipeRefresh = swipeRefreshLayout,
|
swipeRefresh = swipeRefreshLayout,
|
||||||
tabCollectionStorage = tabCollectionStorage
|
tabCollectionStorage = tabCollectionStorage,
|
||||||
|
bookmarkTapped = mockk(),
|
||||||
|
readerModeController = mockk(),
|
||||||
|
sessionManager = mockk(),
|
||||||
|
store = mockk()
|
||||||
)
|
)
|
||||||
|
|
||||||
mockkStatic(
|
mockkStatic(
|
||||||
@ -338,7 +337,6 @@ class DefaultBrowserToolbarControllerTest {
|
|||||||
|
|
||||||
controller.handleToolbarItemInteraction(item)
|
controller.handleToolbarItemInteraction(item)
|
||||||
|
|
||||||
verify { bottomSheetBehavior.state = QuickActionSheetBehavior.STATE_COLLAPSED }
|
|
||||||
verify { findInPageLauncher() }
|
verify { findInPageLauncher() }
|
||||||
verify { metrics.track(Event.FindInPageOpened) }
|
verify { metrics.track(Event.FindInPageOpened) }
|
||||||
}
|
}
|
||||||
@ -466,11 +464,14 @@ class DefaultBrowserToolbarControllerTest {
|
|||||||
customTabSession = currentSession,
|
customTabSession = currentSession,
|
||||||
getSupportUrl = getSupportUrl,
|
getSupportUrl = getSupportUrl,
|
||||||
openInFenixIntent = openInFenixIntent,
|
openInFenixIntent = openInFenixIntent,
|
||||||
bottomSheetBehavior = bottomSheetBehavior,
|
|
||||||
scope = scope,
|
scope = scope,
|
||||||
browserLayout = browserLayout,
|
browserLayout = browserLayout,
|
||||||
swipeRefresh = swipeRefreshLayout,
|
swipeRefresh = swipeRefreshLayout,
|
||||||
tabCollectionStorage = tabCollectionStorage
|
tabCollectionStorage = tabCollectionStorage,
|
||||||
|
bookmarkTapped = mockk(),
|
||||||
|
readerModeController = mockk(),
|
||||||
|
sessionManager = mockk(),
|
||||||
|
store = mockk()
|
||||||
)
|
)
|
||||||
|
|
||||||
val sessionManager: SessionManager = mockk(relaxed = true)
|
val sessionManager: SessionManager = mockk(relaxed = true)
|
||||||
|
@ -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)) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -140,39 +140,6 @@ class SettingsTest {
|
|||||||
assertTrue(settings.isTelemetryEnabled)
|
assertTrue(settings.isTelemetryEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun autoBounceQuickActionSheetCount() {
|
|
||||||
// When just created
|
|
||||||
// Then
|
|
||||||
assertEquals(0, settings.autoBounceQuickActionSheetCount)
|
|
||||||
|
|
||||||
// When
|
|
||||||
settings.incrementAutomaticBounceQuickActionSheetCount()
|
|
||||||
settings.incrementAutomaticBounceQuickActionSheetCount()
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertEquals(2, settings.autoBounceQuickActionSheetCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun shouldAutoBounceQuickActionSheet() {
|
|
||||||
// When just created
|
|
||||||
// Then
|
|
||||||
assertTrue(settings.shouldAutoBounceQuickActionSheet)
|
|
||||||
|
|
||||||
// When
|
|
||||||
settings.incrementAutomaticBounceQuickActionSheetCount()
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertTrue(settings.shouldAutoBounceQuickActionSheet)
|
|
||||||
|
|
||||||
// When
|
|
||||||
settings.incrementAutomaticBounceQuickActionSheetCount()
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertFalse(settings.shouldAutoBounceQuickActionSheet)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showLoginsDialogWarningSync() {
|
fun showLoginsDialogWarningSync() {
|
||||||
// When just created
|
// When just created
|
||||||
|
@ -111,12 +111,6 @@ The following metrics are added to the ping:
|
|||||||
| qr_scanner.navigation_denied |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "deny" on the prompt, putting the user back to the scanning view |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-03-01 |
|
| qr_scanner.navigation_denied |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped "deny" on the prompt, putting the user back to the scanning view |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-03-01 |
|
||||||
| qr_scanner.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the QR scanner |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-03-01 |
|
| qr_scanner.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the QR scanner |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-03-01 |
|
||||||
| qr_scanner.prompt_displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user scanned a QR code, causing a confirmation prompt to display asking if they want to navigate to the page |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-03-01 |
|
| qr_scanner.prompt_displayed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user scanned a QR code, causing a confirmation prompt to display asking if they want to navigate to the page |[1](https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967)||2020-03-01 |
|
||||||
| quick_action_sheet.bookmark_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the bookmark button |[1](https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466)||2020-03-01 |
|
|
||||||
| quick_action_sheet.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed the quick action sheet UI |[1](https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466)||2020-03-01 |
|
|
||||||
| quick_action_sheet.download_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the download button |[1](https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466)||2020-03-01 |
|
|
||||||
| quick_action_sheet.open_app_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the open in app button |[1](https://github.com/mozilla-mobile/fenix/pull/4629)||2020-03-01 |
|
|
||||||
| quick_action_sheet.opened |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user opened the quick action sheet UI |[1](https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466)||2020-03-01 |
|
|
||||||
| quick_action_sheet.share_tapped |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the share button |[1](https://github.com/mozilla-mobile/fenix/pull/1362#issuecomment-479668466)||2020-03-01 |
|
|
||||||
| reader_mode.appearance |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the appearance button |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-03-01 |
|
| reader_mode.appearance |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user tapped the appearance button |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-03-01 |
|
||||||
| reader_mode.available |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Reader mode is available for the current page |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-03-01 |
|
| reader_mode.available |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |Reader mode is available for the current page |[1](https://github.com/mozilla-mobile/fenix/pull/3941)||2020-03-01 |
|
||||||
| reader_mode.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed reader mode |[1](https://github.com/mozilla-mobile/fenix/pull/4328)||2020-03-01 |
|
| reader_mode.closed |[event](https://mozilla.github.io/glean/book/user/metrics/event.html) |A user closed reader mode |[1](https://github.com/mozilla-mobile/fenix/pull/4328)||2020-03-01 |
|
||||||
|
Loading…
Reference in New Issue
Block a user