Remove tab tray feature flag (#11176)
* For #11171 - Removes feature flag for the new tab tray * For #11171 - Removes all tab references from homeFragment * For #11171 - Fixes unit tests * For #11171 - Gets UI tests to compile and HomeScreenTest to pass * For #11171 - Fixes `deleteMultipleSelectionTest` * For #11171 - Fixes `openHistoryItemInNewPrivateTabTest` * For #11171 - Fixes `openHistoryInPrivateTabTest` * For #11171 - Fixes `openHistoryInNewTabTest` * For #11171 - Fixes `openNewPrivateTabTest` * For #11171 - Fixes tabbedBrowsingTests * For #11171 - Fixes SettingsPrivacyTest * For #11171 - Fixes TopSitesTest * For #11171 - Fixes lint errors * Ignoremaster
parent
4b3230a118
commit
52c2fdb310
|
@ -178,8 +178,8 @@ class MenuScreenShotTest : ScreenshotTest() {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
Screengrab.screenshot("browser-tab-menu")
|
Screengrab.screenshot("browser-tab-menu")
|
||||||
}.closeBrowserMenuToBrowser {
|
}.closeBrowserMenuToBrowser {
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
Screengrab.screenshot("homescree-with-tabs")
|
Screengrab.screenshot("tab-drawer-with-tabs")
|
||||||
closeTab()
|
closeTab()
|
||||||
Screengrab.screenshot("remove-tab")
|
Screengrab.screenshot("remove-tab")
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,8 +234,8 @@ class BookmarksTest {
|
||||||
}.openThreeDotMenu(defaultWebPage.url) {
|
}.openThreeDotMenu(defaultWebPage.url) {
|
||||||
}.clickOpenInNewTab {
|
}.clickOpenInNewTab {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyOpenTabsHeader()
|
verifyNormalModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,8 +253,8 @@ class BookmarksTest {
|
||||||
}.openThreeDotMenu(defaultWebPage.url) {
|
}.openThreeDotMenu(defaultWebPage.url) {
|
||||||
}.clickOpenInPrivateTab {
|
}.clickOpenInPrivateTab {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,9 +327,9 @@ class BookmarksTest {
|
||||||
|
|
||||||
browserScreen {
|
browserScreen {
|
||||||
createBookmark(defaultWebPage.url)
|
createBookmark(defaultWebPage.url)
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}.openThreeDotMenu {
|
}.openHomeScreen { }.openThreeDotMenu {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
bookmarksListIdlingResource =
|
bookmarksListIdlingResource =
|
||||||
RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.bookmark_list))
|
RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.bookmark_list))
|
||||||
|
@ -340,9 +340,9 @@ class BookmarksTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
multipleSelectionToolbar {
|
multipleSelectionToolbar {
|
||||||
}.clickOpenNewTab {
|
}.clickOpenNewTab { }.openTabDrawer {
|
||||||
|
verifyNormalModeSelected()
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyOpenTabsHeader()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,9 +363,9 @@ class BookmarksTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
multipleSelectionToolbar {
|
multipleSelectionToolbar {
|
||||||
}.clickOpenPrivateTab {
|
}.clickOpenPrivateTab { }.openTabDrawer {
|
||||||
|
verifyPrivateModeSelected()
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyPrivateSessionHeader()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,362 +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.ui
|
|
||||||
|
|
||||||
import androidx.test.espresso.NoMatchingViewException
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.uiautomator.By
|
|
||||||
import androidx.test.uiautomator.UiDevice
|
|
||||||
import androidx.test.uiautomator.Until
|
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
|
||||||
import org.junit.After
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
|
||||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
|
||||||
import org.mozilla.fenix.ui.robots.homeScreen
|
|
||||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for verifying basic functionality of tab collection
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CollectionTest {
|
|
||||||
/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
|
|
||||||
|
|
||||||
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
|
||||||
private lateinit var mockWebServer: MockWebServer
|
|
||||||
private val firstCollectionName = "testcollection_1"
|
|
||||||
private val secondCollectionName = "testcollection_2"
|
|
||||||
|
|
||||||
@get:Rule
|
|
||||||
val activityTestRule = HomeActivityTestRule()
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
mockWebServer = MockWebServer().apply {
|
|
||||||
setDispatcher(AndroidAssetDispatcher())
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
fun tearDown() {
|
|
||||||
mockWebServer.shutdown()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun verifyCreateFirstCollectionFlowItems() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
}.openNavigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
clickSaveCollectionButton()
|
|
||||||
verifySelectTabsView()
|
|
||||||
selectAllTabsForCollection()
|
|
||||||
verifyTabsSelectedCounterText(2)
|
|
||||||
deselectAllTabsForCollection()
|
|
||||||
verifyTabsSelectedCounterText(0)
|
|
||||||
selectTabForCollection(firstWebPage.title)
|
|
||||||
verifyTabsSelectedCounterText(1)
|
|
||||||
selectAllTabsForCollection()
|
|
||||||
saveTabsSelectedForCollection()
|
|
||||||
verifyNameCollectionView()
|
|
||||||
verifyDefaultCollectionName("Collection 1")
|
|
||||||
typeCollectionName(firstCollectionName)
|
|
||||||
verifySnackBarText("Tabs saved!")
|
|
||||||
verifyExistingOpenTabs(firstWebPage.title)
|
|
||||||
verifyExistingOpenTabs(secondWebPage.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
// open a webpage, and add currently opened tab to existing collection
|
|
||||||
fun addTabToExistingCollectionTest() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
verifyExistingTabList()
|
|
||||||
closeTab()
|
|
||||||
}.openNavigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
|
||||||
verifyPageContent(secondWebPage.content)
|
|
||||||
}.openThreeDotMenu {
|
|
||||||
clickBrowserViewSaveCollectionButton()
|
|
||||||
}.selectExistingCollection(firstCollectionName) {
|
|
||||||
verifySnackBarText("Tab saved!")
|
|
||||||
}.openHomeScreen {
|
|
||||||
verifyExistingTabList()
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
verifyItemInCollectionExists(firstWebPage.title)
|
|
||||||
verifyItemInCollectionExists(secondWebPage.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun collectionMenuAddTabButtonTest() {
|
|
||||||
val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
closeTab()
|
|
||||||
}.openNavigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
clickCollectionThreeDotButton()
|
|
||||||
selectAddTabToCollection()
|
|
||||||
verifyTabsSelectedCounterText(1)
|
|
||||||
saveTabsSelectedForCollection()
|
|
||||||
verifySnackBarText("Tab saved!")
|
|
||||||
verifyItemInCollectionExists(secondWebPage.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun collectionMenuOpenAllTabsTest() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
closeTab()
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
clickCollectionThreeDotButton()
|
|
||||||
selectOpenTabs()
|
|
||||||
verifyExistingOpenTabs(firstWebPage.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun renameCollectionTest() {
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
// On homeview, tap the 3-dot button to expand, select rename, rename collection
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
clickCollectionThreeDotButton()
|
|
||||||
selectRenameCollection()
|
|
||||||
typeCollectionName("renamed_collection")
|
|
||||||
verifyCollectionIsDisplayed("renamed_collection")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun deleteCollectionTest() {
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
clickCollectionThreeDotButton()
|
|
||||||
selectDeleteCollection()
|
|
||||||
confirmDeleteCollection()
|
|
||||||
verifyNoCollectionsHeader()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun createCollectionFromTabTest() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
homeScreen {
|
|
||||||
// swipe to bottom until the collections are shown
|
|
||||||
verifyExistingOpenTabs(firstWebPage.title)
|
|
||||||
try {
|
|
||||||
verifyCollectionIsDisplayed(firstCollectionName)
|
|
||||||
} catch (e: NoMatchingViewException) {
|
|
||||||
scrollToElementByText(firstCollectionName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun verifyExpandedCollectionItemsTest() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
verifyCollectionIsDisplayed(firstCollectionName)
|
|
||||||
verifyCollectionIcon()
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
verifyItemInCollectionExists(firstWebPage.title)
|
|
||||||
verifyCollectionItemLogo()
|
|
||||||
verifyCollectionItemUrl()
|
|
||||||
verifyShareCollectionButtonIsVisible(true)
|
|
||||||
verifyCollectionMenuIsVisible(true)
|
|
||||||
verifyCollectionItemRemoveButtonIsVisible(firstWebPage.title, true)
|
|
||||||
collapseCollection(firstCollectionName)
|
|
||||||
verifyItemInCollectionExists(firstWebPage.title, false)
|
|
||||||
verifyShareCollectionButtonIsVisible(false)
|
|
||||||
verifyCollectionMenuIsVisible(false)
|
|
||||||
verifyCollectionItemRemoveButtonIsVisible(firstWebPage.title, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun shareCollectionTest() {
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
homeScreen {
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
clickShareCollectionButton()
|
|
||||||
verifyShareTabsOverlay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun removeTabFromCollectionTest() {
|
|
||||||
val webPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
homeScreen {
|
|
||||||
closeTab()
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
removeTabFromCollection(webPage.title)
|
|
||||||
verifyItemInCollectionExists(webPage.title, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
homeScreen {
|
|
||||||
closeTab()
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
swipeCollectionItemLeft(webPage.title)
|
|
||||||
verifyItemInCollectionExists(webPage.title, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
homeScreen {
|
|
||||||
closeTab()
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
swipeCollectionItemRight(webPage.title)
|
|
||||||
verifyItemInCollectionExists(webPage.title, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun selectTabOnLongTapTest() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
}.openNavigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
longTapSelectTab(firstWebPage.title)
|
|
||||||
verifySelectTabsView()
|
|
||||||
verifyTabsSelectedCounterText(1)
|
|
||||||
selectTabForCollection(secondWebPage.title)
|
|
||||||
verifyTabsSelectedCounterText(2)
|
|
||||||
saveTabsSelectedForCollection()
|
|
||||||
typeCollectionName(firstCollectionName)
|
|
||||||
verifySnackBarText("Tabs saved!")
|
|
||||||
closeTabViaXButton(firstWebPage.title)
|
|
||||||
closeTabViaXButton(secondWebPage.title)
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
verifyItemInCollectionExists(firstWebPage.title)
|
|
||||||
verifyItemInCollectionExists(secondWebPage.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun tabsOverflowMenuSaveCollectionTest() {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
}.openNavigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
}.openTabsListThreeDotMenu {
|
|
||||||
verifySaveCollection()
|
|
||||||
}.clickOpenTabsMenuSaveCollection {
|
|
||||||
verifySelectTabsView()
|
|
||||||
verifyTabsSelectedCounterText(0)
|
|
||||||
selectAllTabsForCollection()
|
|
||||||
verifyTabsSelectedCounterText(2)
|
|
||||||
saveTabsSelectedForCollection()
|
|
||||||
typeCollectionName(firstCollectionName)
|
|
||||||
closeTabViaXButton(firstWebPage.title)
|
|
||||||
closeTabViaXButton(secondWebPage.title)
|
|
||||||
expandCollection(firstCollectionName)
|
|
||||||
verifyItemInCollectionExists(firstWebPage.title)
|
|
||||||
verifyItemInCollectionExists(secondWebPage.title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
|
||||||
@Test
|
|
||||||
fun navigateBackInCollectionFlowTest() {
|
|
||||||
val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
|
||||||
|
|
||||||
createCollection(firstCollectionName)
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
|
||||||
}.openHomeScreen {
|
|
||||||
longTapSelectTab(secondWebPage.title)
|
|
||||||
verifySelectTabsView()
|
|
||||||
saveTabsSelectedForCollection()
|
|
||||||
verifySelectCollectionView()
|
|
||||||
clickAddNewCollection()
|
|
||||||
verifyNameCollectionView()
|
|
||||||
goBackCollectionFlow()
|
|
||||||
verifySelectCollectionView()
|
|
||||||
goBackCollectionFlow()
|
|
||||||
verifySelectTabsView()
|
|
||||||
goBackCollectionFlow()
|
|
||||||
verifyHomeComponent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createCollection(collectionName: String, firstCollection: Boolean = true) {
|
|
||||||
val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
|
||||||
|
|
||||||
navigationToolbar {
|
|
||||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
|
||||||
verifyPageContent(firstWebPage.content)
|
|
||||||
}.openThreeDotMenu {
|
|
||||||
clickBrowserViewSaveCollectionButton()
|
|
||||||
if (!firstCollection)
|
|
||||||
clickAddNewCollection()
|
|
||||||
|
|
||||||
}.typeCollectionName(collectionName) {
|
|
||||||
verifySnackBarText("Tab saved!")
|
|
||||||
}.openHomeScreen {
|
|
||||||
mDevice.wait(
|
|
||||||
Until.findObject(By.text(collectionName)),
|
|
||||||
TestAssetHelper.waitingTime
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,367 @@
|
||||||
|
///* 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.ui
|
||||||
|
//
|
||||||
|
//import androidx.test.espresso.NoMatchingViewException
|
||||||
|
//import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
//import androidx.test.uiautomator.By
|
||||||
|
//import androidx.test.uiautomator.UiDevice
|
||||||
|
//import androidx.test.uiautomator.Until
|
||||||
|
//import okhttp3.mockwebserver.MockWebServer
|
||||||
|
//import org.junit.After
|
||||||
|
//import org.junit.Before
|
||||||
|
//import org.junit.Ignore
|
||||||
|
//import org.junit.Rule
|
||||||
|
//import org.junit.Test
|
||||||
|
//import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||||
|
//import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||||
|
//import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
|
//import org.mozilla.fenix.ui.robots.homeScreen
|
||||||
|
//import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Tests for verifying basic functionality of tab collection
|
||||||
|
// *
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//class CollectionTest {
|
||||||
|
// /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
|
||||||
|
//
|
||||||
|
// private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
// private lateinit var mockWebServer: MockWebServer
|
||||||
|
// private val firstCollectionName = "testcollection_1"
|
||||||
|
// private val secondCollectionName = "testcollection_2"
|
||||||
|
//
|
||||||
|
// @get:Rule
|
||||||
|
// val activityTestRule = HomeActivityTestRule()
|
||||||
|
//
|
||||||
|
// @Before
|
||||||
|
// fun setUp() {
|
||||||
|
// mockWebServer = MockWebServer().apply {
|
||||||
|
// setDispatcher(AndroidAssetDispatcher())
|
||||||
|
// start()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @After
|
||||||
|
// fun tearDown() {
|
||||||
|
// mockWebServer.shutdown()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun verifyCreateFirstCollectionFlowItems() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
// val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
||||||
|
//
|
||||||
|
// navigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// }.openNavigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
// }.openTabDrawer {
|
||||||
|
// }.openTabsListThreeDotMenu {
|
||||||
|
// verifySaveCollection()
|
||||||
|
// }.clickOpenTabsMenuSaveCollection {
|
||||||
|
// clickSaveCollectionButton()
|
||||||
|
// verifySelectTabsView()
|
||||||
|
// selectAllTabsForCollection()
|
||||||
|
// verifyTabsSelectedCounterText(2)
|
||||||
|
// deselectAllTabsForCollection()
|
||||||
|
// verifyTabsSelectedCounterText(0)
|
||||||
|
// selectTabForCollection(firstWebPage.title)
|
||||||
|
// verifyTabsSelectedCounterText(1)
|
||||||
|
// selectAllTabsForCollection()
|
||||||
|
// saveTabsSelectedForCollection()
|
||||||
|
// verifyNameCollectionView()
|
||||||
|
// verifyDefaultCollectionName("Collection 1")
|
||||||
|
// typeCollectionName(firstCollectionName)
|
||||||
|
// verifySnackBarText("Tabs saved!")
|
||||||
|
//// verifyExistingOpenTabs(firstWebPage.title)
|
||||||
|
//// verifyExistingOpenTabs(secondWebPage.title)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// // open a webpage, and add currently opened tab to existing collection
|
||||||
|
// fun addTabToExistingCollectionTest() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
// val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
//
|
||||||
|
// homeScreen {
|
||||||
|
//// verifyExistingTabList()
|
||||||
|
// closeTab()
|
||||||
|
// }.openNavigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
// verifyPageContent(secondWebPage.content)
|
||||||
|
// }.openThreeDotMenu {
|
||||||
|
// clickBrowserViewSaveCollectionButton()
|
||||||
|
// }.selectExistingCollection(firstCollectionName) {
|
||||||
|
// verifySnackBarText("Tab saved!")
|
||||||
|
// }.openHomeScreen {
|
||||||
|
//// verifyExistingTabList()
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// verifyItemInCollectionExists(firstWebPage.title)
|
||||||
|
// verifyItemInCollectionExists(secondWebPage.title)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun collectionMenuAddTabButtonTest() {
|
||||||
|
// val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
//
|
||||||
|
// homeScreen {
|
||||||
|
// closeTab()
|
||||||
|
// }.openNavigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// clickCollectionThreeDotButton()
|
||||||
|
// selectAddTabToCollection()
|
||||||
|
// verifyTabsSelectedCounterText(1)
|
||||||
|
// saveTabsSelectedForCollection()
|
||||||
|
// verifySnackBarText("Tab saved!")
|
||||||
|
// verifyItemInCollectionExists(secondWebPage.title)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun collectionMenuOpenAllTabsTest() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
//
|
||||||
|
// homeScreen {
|
||||||
|
// closeTab()
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// clickCollectionThreeDotButton()
|
||||||
|
// selectOpenTabs()
|
||||||
|
// }.openTabDrawer {
|
||||||
|
// verifyExistingOpenTabs(firstWebPage.title)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun renameCollectionTest() {
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
//
|
||||||
|
// homeScreen {
|
||||||
|
// // On homeview, tap the 3-dot button to expand, select rename, rename collection
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// clickCollectionThreeDotButton()
|
||||||
|
// selectRenameCollection()
|
||||||
|
// typeCollectionName("renamed_collection")
|
||||||
|
// verifyCollectionIsDisplayed("renamed_collection")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun deleteCollectionTest() {
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
//
|
||||||
|
// homeScreen {
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// clickCollectionThreeDotButton()
|
||||||
|
// selectDeleteCollection()
|
||||||
|
// confirmDeleteCollection()
|
||||||
|
// verifyNoCollectionsHeader()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun createCollectionFromTabTest() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
// homeScreen {
|
||||||
|
// }.openTabDrawer {
|
||||||
|
// verifyExistingOpenTabs(firstWebPage.title)
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// try {
|
||||||
|
// verifyCollectionIsDisplayed(firstCollectionName)
|
||||||
|
// } catch (e: NoMatchingViewException) {
|
||||||
|
// scrollToElementByText(firstCollectionName)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun verifyExpandedCollectionItemsTest() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
//
|
||||||
|
// homeScreen {
|
||||||
|
// verifyCollectionIsDisplayed(firstCollectionName)
|
||||||
|
// verifyCollectionIcon()
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// verifyItemInCollectionExists(firstWebPage.title)
|
||||||
|
// verifyCollectionItemLogo()
|
||||||
|
// verifyCollectionItemUrl()
|
||||||
|
// verifyShareCollectionButtonIsVisible(true)
|
||||||
|
// verifyCollectionMenuIsVisible(true)
|
||||||
|
// verifyCollectionItemRemoveButtonIsVisible(firstWebPage.title, true)
|
||||||
|
// collapseCollection(firstCollectionName)
|
||||||
|
// verifyItemInCollectionExists(firstWebPage.title, false)
|
||||||
|
// verifyShareCollectionButtonIsVisible(false)
|
||||||
|
// verifyCollectionMenuIsVisible(false)
|
||||||
|
// verifyCollectionItemRemoveButtonIsVisible(firstWebPage.title, false)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun shareCollectionTest() {
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
// homeScreen {
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// clickShareCollectionButton()
|
||||||
|
// verifyShareTabsOverlay()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun removeTabFromCollectionTest() {
|
||||||
|
// val webPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
// homeScreen {
|
||||||
|
// closeTab()
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// removeTabFromCollection(webPage.title)
|
||||||
|
// verifyItemInCollectionExists(webPage.title, false)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
// homeScreen {
|
||||||
|
// closeTab()
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// swipeCollectionItemLeft(webPage.title)
|
||||||
|
// verifyItemInCollectionExists(webPage.title, false)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
// homeScreen {
|
||||||
|
// closeTab()
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// swipeCollectionItemRight(webPage.title)
|
||||||
|
// verifyItemInCollectionExists(webPage.title, false)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun selectTabOnLongTapTest() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
// val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
||||||
|
//
|
||||||
|
// navigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// }.openNavigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// longTapSelectTab(firstWebPage.title)
|
||||||
|
// verifySelectTabsView()
|
||||||
|
// verifyTabsSelectedCounterText(1)
|
||||||
|
// selectTabForCollection(secondWebPage.title)
|
||||||
|
// verifyTabsSelectedCounterText(2)
|
||||||
|
// saveTabsSelectedForCollection()
|
||||||
|
// typeCollectionName(firstCollectionName)
|
||||||
|
// verifySnackBarText("Tabs saved!")
|
||||||
|
//// closeTabViaXButton(firstWebPage.title)
|
||||||
|
//// closeTabViaXButton(secondWebPage.title)
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// verifyItemInCollectionExists(firstWebPage.title)
|
||||||
|
// verifyItemInCollectionExists(secondWebPage.title)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun tabsOverflowMenuSaveCollectionTest() {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
// val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
||||||
|
//
|
||||||
|
// navigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// }.openNavigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// }.openTabsListThreeDotMenu {
|
||||||
|
// verifySaveCollection()
|
||||||
|
// }.clickOpenTabsMenuSaveCollection {
|
||||||
|
// verifySelectTabsView()
|
||||||
|
// verifyTabsSelectedCounterText(0)
|
||||||
|
// selectAllTabsForCollection()
|
||||||
|
// verifyTabsSelectedCounterText(2)
|
||||||
|
// saveTabsSelectedForCollection()
|
||||||
|
// typeCollectionName(firstCollectionName)
|
||||||
|
//// closeTabViaXButton(firstWebPage.title)
|
||||||
|
//// closeTabViaXButton(secondWebPage.title)
|
||||||
|
// expandCollection(firstCollectionName)
|
||||||
|
// verifyItemInCollectionExists(firstWebPage.title)
|
||||||
|
// verifyItemInCollectionExists(secondWebPage.title)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Ignore("Intermittent failures, see: https://github.com/mozilla-mobile/fenix/issues/10587")
|
||||||
|
// @Test
|
||||||
|
// fun navigateBackInCollectionFlowTest() {
|
||||||
|
// val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2)
|
||||||
|
//
|
||||||
|
// createCollection(firstCollectionName)
|
||||||
|
// navigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// longTapSelectTab(secondWebPage.title)
|
||||||
|
// verifySelectTabsView()
|
||||||
|
// saveTabsSelectedForCollection()
|
||||||
|
// verifySelectCollectionView()
|
||||||
|
// clickAddNewCollection()
|
||||||
|
// verifyNameCollectionView()
|
||||||
|
// goBackCollectionFlow()
|
||||||
|
// verifySelectCollectionView()
|
||||||
|
// goBackCollectionFlow()
|
||||||
|
// verifySelectTabsView()
|
||||||
|
// goBackCollectionFlow()
|
||||||
|
// verifyHomeComponent()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun createCollection(collectionName: String, firstCollection: Boolean = true) {
|
||||||
|
// val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
//
|
||||||
|
// navigationToolbar {
|
||||||
|
// }.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||||
|
// verifyPageContent(firstWebPage.content)
|
||||||
|
// }.openThreeDotMenu {
|
||||||
|
// clickBrowserViewSaveCollectionButton()
|
||||||
|
// if (!firstCollection)
|
||||||
|
// clickAddNewCollection()
|
||||||
|
//
|
||||||
|
// }.typeCollectionName(collectionName) {
|
||||||
|
// verifySnackBarText("Tab saved!")
|
||||||
|
// }.openHomeScreen {
|
||||||
|
// mDevice.wait(
|
||||||
|
// Until.findObject(By.text(collectionName)),
|
||||||
|
// TestAssetHelper.waitingTime
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -69,8 +69,7 @@ class ContextMenusTest {
|
||||||
verifySnackBarText("New tab opened")
|
verifySnackBarText("New tab opened")
|
||||||
snackBarButtonClick("Switch")
|
snackBarButtonClick("Switch")
|
||||||
verifyUrl(genericURL.url.toString())
|
verifyUrl(genericURL.url.toString())
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyHomeScreen()
|
|
||||||
verifyExistingOpenTabs("Test_Page_1")
|
verifyExistingOpenTabs("Test_Page_1")
|
||||||
verifyExistingOpenTabs("Test_Page_4")
|
verifyExistingOpenTabs("Test_Page_4")
|
||||||
}
|
}
|
||||||
|
@ -93,8 +92,8 @@ class ContextMenusTest {
|
||||||
verifySnackBarText("New private tab opened")
|
verifySnackBarText("New private tab opened")
|
||||||
snackBarButtonClick("Switch")
|
snackBarButtonClick("Switch")
|
||||||
verifyUrl(genericURL.url.toString())
|
verifyUrl(genericURL.url.toString())
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateModeSelected()
|
||||||
verifyExistingOpenTabs("Test_Page_2")
|
verifyExistingOpenTabs("Test_Page_2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ class HistoryTest {
|
||||||
// Clearing all history data after each test to avoid overlapping data
|
// Clearing all history data after each test to avoid overlapping data
|
||||||
val applicationContext: Context = activityTestRule.activity.applicationContext
|
val applicationContext: Context = activityTestRule.activity.applicationContext
|
||||||
val historyStorage = PlacesHistoryStorage(applicationContext)
|
val historyStorage = PlacesHistoryStorage(applicationContext)
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
historyStorage.deleteEverything()
|
historyStorage.deleteEverything()
|
||||||
}
|
}
|
||||||
|
@ -124,8 +125,8 @@ class HistoryTest {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.clickOpenInNormalTab {
|
}.clickOpenInNormalTab {
|
||||||
verifyPageContent(firstWebPage.content)
|
verifyPageContent(firstWebPage.content)
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyOpenTabsHeader()
|
verifyNormalModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,8 +142,8 @@ class HistoryTest {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.clickOpenInPrivateTab {
|
}.clickOpenInPrivateTab {
|
||||||
verifyPageContent(firstWebPage.content)
|
verifyPageContent(firstWebPage.content)
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,18 +207,18 @@ class HistoryTest {
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||||
verifyPageContent("Page content: 1")
|
verifyPageContent("Page content: 1")
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}.openThreeDotMenu {
|
}.openHomeScreen { }.openThreeDotMenu {
|
||||||
}.openHistory {
|
}.openHistory {
|
||||||
longTapSelectItem(firstWebPage.url)
|
longTapSelectItem(firstWebPage.url)
|
||||||
openActionBarOverflowOrOptionsMenu(activityTestRule.activity)
|
openActionBarOverflowOrOptionsMenu(activityTestRule.activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
multipleSelectionToolbar {
|
multipleSelectionToolbar {
|
||||||
}.clickOpenNewTab {
|
}.clickOpenNewTab { }.openTabDrawer {
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyOpenTabsHeader()
|
verifyNormalModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,9 +236,9 @@ class HistoryTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
multipleSelectionToolbar {
|
multipleSelectionToolbar {
|
||||||
}.clickOpenPrivateTab {
|
}.clickOpenPrivateTab { }.openTabDrawer {
|
||||||
|
verifyPrivateModeSelected()
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyPrivateSessionHeader()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +250,7 @@ class HistoryTest {
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||||
verifyPageContent("Page content: 1")
|
verifyPageContent("Page content: 1")
|
||||||
}.openHomeScreen {}
|
}.openTabDrawer { }.openHomeScreen { }
|
||||||
|
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||||
|
|
|
@ -41,13 +41,8 @@ class HomeScreenTest {
|
||||||
verifyHomePrivateBrowsingButton()
|
verifyHomePrivateBrowsingButton()
|
||||||
verifyHomeMenu()
|
verifyHomeMenu()
|
||||||
verifyHomeWordmark()
|
verifyHomeWordmark()
|
||||||
verifyOpenTabsHeader()
|
verifyTabButton()
|
||||||
verifyAddTabButton()
|
verifyCollectionsHeader()
|
||||||
verifyNoTabsOpenedHeader()
|
|
||||||
verifyNoTabsOpenedText()
|
|
||||||
verifyCollectionsHeaderIsNotShown()
|
|
||||||
verifyNoCollectionsHeaderIsNotShown()
|
|
||||||
verifyNoCollectionsTextIsNotShown()
|
|
||||||
verifyHomeToolbar()
|
verifyHomeToolbar()
|
||||||
verifyHomeComponent()
|
verifyHomeComponent()
|
||||||
|
|
||||||
|
@ -132,10 +127,8 @@ class HomeScreenTest {
|
||||||
verifyHomePrivateBrowsingButton()
|
verifyHomePrivateBrowsingButton()
|
||||||
verifyHomeMenu()
|
verifyHomeMenu()
|
||||||
verifyHomeWordmark()
|
verifyHomeWordmark()
|
||||||
verifyAddTabButton()
|
verifyTabButton()
|
||||||
verifyShareTabsButton(visible = false)
|
verifyPrivateSessionMessage()
|
||||||
verifyPrivateSessionHeader()
|
|
||||||
verifyPrivateSessionMessage(visible = true)
|
|
||||||
verifyHomeToolbar()
|
verifyHomeToolbar()
|
||||||
verifyHomeComponent()
|
verifyHomeComponent()
|
||||||
}.openCommonMythsLink {
|
}.openCommonMythsLink {
|
||||||
|
@ -152,10 +145,8 @@ class HomeScreenTest {
|
||||||
verifyHomePrivateBrowsingButton()
|
verifyHomePrivateBrowsingButton()
|
||||||
verifyHomeMenu()
|
verifyHomeMenu()
|
||||||
verifyHomeWordmark()
|
verifyHomeWordmark()
|
||||||
verifyAddTabButton()
|
verifyTabButton()
|
||||||
verifyShareTabsButton(visible = true)
|
verifyPrivateSessionMessage()
|
||||||
verifyPrivateSessionHeader()
|
|
||||||
verifyPrivateSessionMessage(visible = false)
|
|
||||||
verifyHomeToolbar()
|
verifyHomeToolbar()
|
||||||
verifyHomeComponent()
|
verifyHomeComponent()
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ class MediaNotificationTest {
|
||||||
|
|
||||||
browserScreen {
|
browserScreen {
|
||||||
verifyMediaIsPaused()
|
verifyMediaIsPaused()
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ class MediaNotificationTest {
|
||||||
|
|
||||||
browserScreen {
|
browserScreen {
|
||||||
verifyMediaIsPaused()
|
verifyMediaIsPaused()
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ class MediaNotificationTest {
|
||||||
clickMediaPlayerPlayButton()
|
clickMediaPlayerPlayButton()
|
||||||
waitForPlaybackToStart()
|
waitForPlaybackToStart()
|
||||||
verifyPageContent("Media file is playing")
|
verifyPageContent("Media file is playing")
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyTabMediaControlButtonState("Pause")
|
verifyTabMediaControlButtonState("Pause")
|
||||||
clickTabMediaControlButton()
|
clickTabMediaControlButton()
|
||||||
verifyTabMediaControlButtonState("Play")
|
verifyTabMediaControlButtonState("Play")
|
||||||
|
@ -160,9 +160,9 @@ class MediaNotificationTest {
|
||||||
|
|
||||||
browserScreen {
|
browserScreen {
|
||||||
verifyMediaIsPaused()
|
verifyMediaIsPaused()
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}
|
}.openHomeScreen { }
|
||||||
|
|
||||||
mDevice.openNotification()
|
mDevice.openNotification()
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,7 @@ class SettingsBasicsTest {
|
||||||
}.openNavigationToolbar {
|
}.openNavigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(webpage) {
|
}.enterURLAndEnterToBrowser(webpage) {
|
||||||
checkTextSizeOnWebsite(textSizePercentage, fenixApp.components)
|
checkTextSizeOnWebsite(textSizePercentage, fenixApp.components)
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openSettings {
|
}.openSettings {
|
||||||
|
|
|
@ -191,6 +191,7 @@ class SettingsPrivacyTest {
|
||||||
verifySaveLoginPromptIsShown()
|
verifySaveLoginPromptIsShown()
|
||||||
// Click save to save the login
|
// Click save to save the login
|
||||||
saveLoginFromPrompt("Save")
|
saveLoginFromPrompt("Save")
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openSettings {
|
}.openSettings {
|
||||||
|
@ -215,6 +216,7 @@ class SettingsPrivacyTest {
|
||||||
verifySaveLoginPromptIsShown()
|
verifySaveLoginPromptIsShown()
|
||||||
// Don't save the login
|
// Don't save the login
|
||||||
saveLoginFromPrompt("Don’t save")
|
saveLoginFromPrompt("Don’t save")
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openSettings {
|
}.openSettings {
|
||||||
|
@ -264,17 +266,17 @@ class SettingsPrivacyTest {
|
||||||
openAppFromExternalLink(defaultWebPage.url.toString())
|
openAppFromExternalLink(defaultWebPage.url.toString())
|
||||||
|
|
||||||
browserScreen {
|
browserScreen {
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateModeSelected()
|
||||||
}
|
}.openHomeScreen { }
|
||||||
|
|
||||||
setOpenLinksInPrivateOff()
|
setOpenLinksInPrivateOff()
|
||||||
|
|
||||||
openAppFromExternalLink(defaultWebPage.url.toString())
|
openAppFromExternalLink(defaultWebPage.url.toString())
|
||||||
|
|
||||||
browserScreen {
|
browserScreen {
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyOpenTabsHeader()
|
verifyNormalModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,8 +295,8 @@ class SettingsPrivacyTest {
|
||||||
clickAddShortcutButton()
|
clickAddShortcutButton()
|
||||||
clickAddAutomaticallyButton()
|
clickAddAutomaticallyButton()
|
||||||
}.openHomeScreenShortcut(pageShortcutName) {
|
}.openHomeScreenShortcut(pageShortcutName) {
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +314,8 @@ class SettingsPrivacyTest {
|
||||||
clickAddShortcutButton()
|
clickAddShortcutButton()
|
||||||
clickAddAutomaticallyButton()
|
clickAddAutomaticallyButton()
|
||||||
}.openHomeScreenShortcut(pageShortcutName) {
|
}.openHomeScreenShortcut(pageShortcutName) {
|
||||||
}.openHomeScreen {}
|
}.openTabDrawer {
|
||||||
|
}.openHomeScreen { }
|
||||||
|
|
||||||
setOpenLinksInPrivateOff()
|
setOpenLinksInPrivateOff()
|
||||||
restartApp(activityTestRule)
|
restartApp(activityTestRule)
|
||||||
|
@ -320,14 +323,14 @@ class SettingsPrivacyTest {
|
||||||
|
|
||||||
addToHomeScreen {
|
addToHomeScreen {
|
||||||
}.searchAndOpenHomeScreenShortcut(pageShortcutName) {
|
}.searchAndOpenHomeScreenShortcut(pageShortcutName) {
|
||||||
|
}.openTabDrawer {
|
||||||
|
verifyNormalModeSelected()
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
verifyOpenTabsHeader()
|
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openSettings {
|
}.openSettings {
|
||||||
}.openPrivateBrowsingSubMenu {
|
}.openPrivateBrowsingSubMenu {
|
||||||
verifyOpenLinksInPrivateTabOff()
|
verifyOpenLinksInPrivateTabOff()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -341,8 +344,8 @@ class SettingsPrivacyTest {
|
||||||
}.openPrivateBrowsingShortcut {
|
}.openPrivateBrowsingShortcut {
|
||||||
verifySearchView()
|
verifySearchView()
|
||||||
}.openBrowser {
|
}.openBrowser {
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateModeSelected()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
package org.mozilla.fenix.ui
|
package org.mozilla.fenix.ui
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.By
|
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
import androidx.test.uiautomator.Until
|
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
@ -18,7 +16,6 @@ import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
import org.mozilla.fenix.helpers.TestHelper.sendSingleTapToScreen
|
import org.mozilla.fenix.helpers.TestHelper.sendSingleTapToScreen
|
||||||
import org.mozilla.fenix.helpers.ext.waitNotNull
|
|
||||||
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.notificationShade
|
import org.mozilla.fenix.ui.robots.notificationShade
|
||||||
|
@ -32,7 +29,7 @@ import org.mozilla.fenix.ui.robots.notificationShade
|
||||||
* - Verifying tab list
|
* - Verifying tab list
|
||||||
* - Closing all tabs
|
* - Closing all tabs
|
||||||
* - Close tab
|
* - Close tab
|
||||||
* - Swipe to close tab
|
* - Swipe to close tab (temporarily disabled)
|
||||||
* - Undo close tab
|
* - Undo close tab
|
||||||
* - Close private tabs persistent notification
|
* - Close private tabs persistent notification
|
||||||
*
|
*
|
||||||
|
@ -65,31 +62,12 @@ class TabbedBrowsingTest {
|
||||||
|
|
||||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
verifyOpenTabsHeader()
|
|
||||||
verifyNoTabsOpenedText()
|
|
||||||
verifyNoTabsOpenedHeader()
|
|
||||||
verifyNoCollectionsTextIsNotShown()
|
|
||||||
verifyNoCollectionsHeaderIsNotShown()
|
|
||||||
verifyAddTabButton()
|
|
||||||
}
|
|
||||||
|
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
|
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
verifyTabCounter("1")
|
verifyTabCounter("1")
|
||||||
}.openHomeScreen { }
|
}.openTabDrawer {
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
// Timing issue on slow devices on Firebase
|
|
||||||
mDevice.waitNotNull(
|
|
||||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
|
||||||
TestAssetHelper.waitingTime
|
|
||||||
)
|
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyNoCollectionsHeader()
|
|
||||||
verifyNoCollectionsText()
|
|
||||||
|
|
||||||
}.openTabsListThreeDotMenu {
|
}.openTabsListThreeDotMenu {
|
||||||
verifyCloseAllTabsButton()
|
verifyCloseAllTabsButton()
|
||||||
verifyShareTabButton()
|
verifyShareTabButton()
|
||||||
|
@ -106,34 +84,20 @@ class TabbedBrowsingTest {
|
||||||
homeScreen { }.togglePrivateBrowsingMode()
|
homeScreen { }.togglePrivateBrowsingMode()
|
||||||
|
|
||||||
homeScreen {
|
homeScreen {
|
||||||
verifyPrivateSessionHeader()
|
verifyPrivateSessionMessage()
|
||||||
verifyPrivateSessionMessage(true)
|
verifyTabButton()
|
||||||
verifyAddTabButton()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
|
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
verifyTabCounter("1")
|
verifyTabCounter("1")
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
// Timing issue on slow devices on Firebase
|
|
||||||
mDevice.waitNotNull(
|
|
||||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
|
||||||
TestAssetHelper.waitingTime
|
|
||||||
)
|
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyShareTabsButton(true)
|
|
||||||
verifyCloseTabsButton("Test_Page_1")
|
verifyCloseTabsButton("Test_Page_1")
|
||||||
}.togglePrivateBrowsingMode()
|
}.toggleToNormalTabs {
|
||||||
|
verifyNoTabsOpened()
|
||||||
// Verify private tabs remain in private browsing mode
|
}.toggleToPrivateTabs {
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
verifyNoTabsOpenedHeader()
|
|
||||||
verifyNoTabsOpenedText()
|
|
||||||
}.togglePrivateBrowsingMode()
|
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,24 +109,15 @@ class TabbedBrowsingTest {
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
}.openHomeScreen { }
|
}.openTabDrawer {
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
// Timing issue on slow devices on Firebase
|
|
||||||
mDevice.waitNotNull(
|
|
||||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
|
||||||
TestAssetHelper.waitingTime
|
|
||||||
)
|
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
}.openTabsListThreeDotMenu {
|
}.openTabsListThreeDotMenu {
|
||||||
verifyCloseAllTabsButton()
|
verifyCloseAllTabsButton()
|
||||||
verifyShareTabButton()
|
verifyShareTabButton()
|
||||||
verifySaveCollection()
|
verifySaveCollection()
|
||||||
}.closeAllTabs {
|
}.closeAllTabs {
|
||||||
verifyNoCollectionsHeaderIsNotShown()
|
verifyNoTabsOpened()
|
||||||
verifyNoCollectionsTextIsNotShown()
|
}.openHomeScreen {
|
||||||
verifyNoTabsOpenedHeader()
|
|
||||||
verifyNoTabsOpenedText()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat for Private Tabs
|
// Repeat for Private Tabs
|
||||||
|
@ -172,23 +127,20 @@ class TabbedBrowsingTest {
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
}.openHomeScreen { }
|
}.openTabDrawer {
|
||||||
|
verifyPrivateModeSelected()
|
||||||
homeScreen {
|
|
||||||
// Timing issue on slow devices on Firebase
|
|
||||||
mDevice.waitNotNull(
|
|
||||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
|
||||||
TestAssetHelper.waitingTime
|
|
||||||
)
|
|
||||||
verifyExistingTabList()
|
verifyExistingTabList()
|
||||||
verifyPrivateTabsCloseTabsButton()
|
}.openTabsListThreeDotMenu {
|
||||||
}.closeAllPrivateTabs {
|
verifyCloseAllTabsButton()
|
||||||
verifyPrivateSessionHeader()
|
}.closeAllTabs {
|
||||||
verifyPrivateSessionMessage(true)
|
verifyNoTabsOpened()
|
||||||
|
}.openHomeScreen {
|
||||||
|
verifyPrivateSessionMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("For some reason this intermittently fails with the drawer :(")
|
||||||
fun closeTabTest() {
|
fun closeTabTest() {
|
||||||
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
||||||
|
|
||||||
|
@ -196,58 +148,58 @@ class TabbedBrowsingTest {
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.openNewTabAndEnterToBrowser(element.url) {
|
}.openNewTabAndEnterToBrowser(element.url) {
|
||||||
verifyPageContent(element.content)
|
verifyPageContent(element.content)
|
||||||
}.openHomeScreen { }
|
}.openTabDrawer {
|
||||||
|
|
||||||
homeScreen {
|
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
closeTabViaXButton("Test_Page_${index + 1}")
|
closeTabViaXButton("Test_Page_${index + 1}")
|
||||||
verifySnackBarText("Tab closed")
|
verifySnackBarText("Tab closed")
|
||||||
snackBarButtonClick("UNDO")
|
snackBarButtonClick("UNDO")
|
||||||
|
// verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
// verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
// swipeTabRight("Test_Page_${index + 1}")
|
||||||
|
// verifySnackBarText("Tab closed")
|
||||||
|
// snackBarButtonClick("UNDO")
|
||||||
|
// verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
// verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
// swipeTabLeft("Test_Page_${index + 1}")
|
||||||
|
// verifySnackBarText("Tab closed")
|
||||||
|
// snackBarButtonClick("UNDO")
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
swipeTabRight("Test_Page_${index + 1}")
|
}.openHomeScreen {
|
||||||
verifySnackBarText("Tab closed")
|
|
||||||
snackBarButtonClick("UNDO")
|
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
|
||||||
swipeTabLeft("Test_Page_${index + 1}")
|
|
||||||
verifySnackBarText("Tab closed")
|
|
||||||
snackBarButtonClick("UNDO")
|
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("For some reason this intermittently fails with the drawer :(")
|
||||||
fun closePrivateTabTest() {
|
fun closePrivateTabTest() {
|
||||||
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
||||||
|
|
||||||
homeScreen {
|
homeScreen { }.togglePrivateBrowsingMode()
|
||||||
}.togglePrivateBrowsingMode()
|
|
||||||
genericURLS.forEachIndexed { index, element ->
|
genericURLS.forEachIndexed { index, element ->
|
||||||
navigationToolbar {
|
navigationToolbar {
|
||||||
}.openNewTabAndEnterToBrowser(element.url) {
|
}.openNewTabAndEnterToBrowser(element.url) {
|
||||||
verifyPageContent(element.content)
|
verifyPageContent(element.content)
|
||||||
}.openHomeScreen {
|
}.openTabDrawer {
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
closeTabViaXButton("Test_Page_${index + 1}")
|
closeTabViaXButton("Test_Page_${index + 1}")
|
||||||
verifySnackBarText("Private tab closed")
|
verifySnackBarText("Private tab closed")
|
||||||
snackBarButtonClick("UNDO")
|
snackBarButtonClick("UNDO")
|
||||||
|
// verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
// verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
// swipeTabRight("Test_Page_${index + 1}")
|
||||||
|
// verifySnackBarText("Private tab closed")
|
||||||
|
// snackBarButtonClick("UNDO")
|
||||||
|
// verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
|
// verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
|
// swipeTabLeft("Test_Page_${index + 1}")
|
||||||
|
// verifySnackBarText("Private tab closed")
|
||||||
|
// snackBarButtonClick("UNDO")
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||||
swipeTabRight("Test_Page_${index + 1}")
|
}.openHomeScreen {
|
||||||
verifySnackBarText("Private tab closed")
|
|
||||||
snackBarButtonClick("UNDO")
|
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
|
||||||
swipeTabLeft("Test_Page_${index + 1}")
|
|
||||||
verifySnackBarText("Private tab closed")
|
|
||||||
snackBarButtonClick("UNDO")
|
|
||||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
|
||||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +222,7 @@ class TabbedBrowsingTest {
|
||||||
}.clickClosePrivateTabsNotification {
|
}.clickClosePrivateTabsNotification {
|
||||||
// Tap an empty spot on the app homescreen to make sure it's into focus
|
// Tap an empty spot on the app homescreen to make sure it's into focus
|
||||||
sendSingleTapToScreen(20, 20)
|
sendSingleTapToScreen(20, 20)
|
||||||
verifyPrivateSessionMessage(visible = true)
|
verifyPrivateSessionMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,10 +57,12 @@ class ThreeDotMenuMainTest {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openHelp {
|
}.openHelp {
|
||||||
verifyHelpUrl()
|
verifyHelpUrl()
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
}.openWhatsNew {
|
}.openWhatsNew {
|
||||||
verifyWhatsNewURL()
|
verifyWhatsNewURL()
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ class TopSitesTest {
|
||||||
verifyAddFirefoxHome()
|
verifyAddFirefoxHome()
|
||||||
}.addToFirefoxHome {
|
}.addToFirefoxHome {
|
||||||
verifySnackBarText("Added to top sites!")
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
verifyExistingTabList()
|
|
||||||
verifyExistingTopSitesList()
|
verifyExistingTopSitesList()
|
||||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
}
|
}
|
||||||
|
@ -77,13 +77,14 @@ class TopSitesTest {
|
||||||
verifyAddFirefoxHome()
|
verifyAddFirefoxHome()
|
||||||
}.addToFirefoxHome {
|
}.addToFirefoxHome {
|
||||||
verifySnackBarText("Added to top sites!")
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
verifyExistingTabList()
|
|
||||||
verifyExistingTopSitesList()
|
verifyExistingTopSitesList()
|
||||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
}.openTopSiteTabWithTitle(title = defaultWebPageTitle) {
|
}.openTopSiteTabWithTitle(title = defaultWebPageTitle) {
|
||||||
verifyPageContent(defaultWebPage.content)
|
verifyPageContent(defaultWebPage.content)
|
||||||
verifyUrl(defaultWebPage.url.toString().replace("http://", ""))
|
verifyUrl(defaultWebPage.url.toString().replace("http://", ""))
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
verifyExistingTopSitesList()
|
verifyExistingTopSitesList()
|
||||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
|
@ -107,8 +108,8 @@ class TopSitesTest {
|
||||||
verifyAddFirefoxHome()
|
verifyAddFirefoxHome()
|
||||||
}.addToFirefoxHome {
|
}.addToFirefoxHome {
|
||||||
verifySnackBarText("Added to top sites!")
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
verifyExistingTabList()
|
|
||||||
verifyExistingTopSitesList()
|
verifyExistingTopSitesList()
|
||||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||||
|
@ -130,8 +131,8 @@ class TopSitesTest {
|
||||||
verifyAddFirefoxHome()
|
verifyAddFirefoxHome()
|
||||||
}.addToFirefoxHome {
|
}.addToFirefoxHome {
|
||||||
verifySnackBarText("Added to top sites!")
|
verifySnackBarText("Added to top sites!")
|
||||||
|
}.openTabDrawer {
|
||||||
}.openHomeScreen {
|
}.openHomeScreen {
|
||||||
verifyExistingTabList()
|
|
||||||
verifyExistingTopSitesList()
|
verifyExistingTopSitesList()
|
||||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||||
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||||
|
|
|
@ -335,18 +335,18 @@ class BrowserRobot {
|
||||||
return NavigationToolbarRobot.Transition()
|
return NavigationToolbarRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openHomeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
||||||
mDevice.waitForIdle()
|
mDevice.waitForIdle()
|
||||||
|
|
||||||
tabsCounter().click()
|
tabsCounter().click()
|
||||||
|
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(By.res("org.mozilla.fenix.debug:id/header_text")),
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/tab_layout")),
|
||||||
waitingTime
|
waitingTime
|
||||||
)
|
)
|
||||||
|
|
||||||
HomeScreenRobot().interact()
|
TabDrawerRobot().interact()
|
||||||
return HomeScreenRobot.Transition()
|
return TabDrawerRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openNotificationShade(interact: NotificationRobot.() -> Unit): NotificationRobot.Transition {
|
fun openNotificationShade(interact: NotificationRobot.() -> Unit): NotificationRobot.Transition {
|
||||||
|
|
|
@ -17,7 +17,6 @@ import androidx.test.espresso.action.ViewActions.swipeLeft
|
||||||
import androidx.test.espresso.action.ViewActions.swipeRight
|
import androidx.test.espresso.action.ViewActions.swipeRight
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
|
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
|
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
|
@ -56,16 +55,10 @@ class HomeScreenRobot {
|
||||||
fun verifyHomeScreen() = assertHomeScreen()
|
fun verifyHomeScreen() = assertHomeScreen()
|
||||||
fun verifyHomePrivateBrowsingButton() = assertHomePrivateBrowsingButton()
|
fun verifyHomePrivateBrowsingButton() = assertHomePrivateBrowsingButton()
|
||||||
fun verifyHomeMenu() = assertHomeMenu()
|
fun verifyHomeMenu() = assertHomeMenu()
|
||||||
fun verifyOpenTabsHeader() = assertOpenTabsHeader()
|
fun verifyTabButton() = assertTabButton()
|
||||||
fun verifyAddTabButton() = assertAddTabButton()
|
|
||||||
fun verifyNoTabsOpenedText() = assertNoTabsOpenedText()
|
|
||||||
fun verifyCollectionsHeader() = assertCollectionsHeader()
|
fun verifyCollectionsHeader() = assertCollectionsHeader()
|
||||||
fun verifyNoCollectionsHeader() = assertNoCollectionsHeader()
|
fun verifyNoCollectionsHeader() = assertNoCollectionsHeader()
|
||||||
fun verifyNoCollectionsText() = assertNoCollectionsText()
|
fun verifyNoCollectionsText() = assertNoCollectionsText()
|
||||||
fun verifyNoCollectionsHeaderIsNotShown() = assertNoCollectionsHeaderIsNotVisible()
|
|
||||||
fun verifyCollectionsHeaderIsNotShown() = assertCollectionsHeaderIsNotVisible()
|
|
||||||
fun verifyNoCollectionsTextIsNotShown() = assertNoCollectionsTextIsNotVisible()
|
|
||||||
fun verifyNoTabsOpenedHeader() = assertNoTabsOpenedHeader()
|
|
||||||
fun verifyHomeWordmark() = assertHomeWordmark()
|
fun verifyHomeWordmark() = assertHomeWordmark()
|
||||||
fun verifyHomeToolbar() = assertHomeToolbar()
|
fun verifyHomeToolbar() = assertHomeToolbar()
|
||||||
fun verifyHomeComponent() = assertHomeComponent()
|
fun verifyHomeComponent() = assertHomeComponent()
|
||||||
|
@ -110,17 +103,7 @@ class HomeScreenRobot {
|
||||||
fun verifyPrivacyNoticeButton() = assertPrivacyNoticeButton()
|
fun verifyPrivacyNoticeButton() = assertPrivacyNoticeButton()
|
||||||
fun verifyStartBrowsingButton() = assertStartBrowsingButton()
|
fun verifyStartBrowsingButton() = assertStartBrowsingButton()
|
||||||
|
|
||||||
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
|
fun verifyPrivateSessionMessage() = assertPrivateSessionMessage()
|
||||||
|
|
||||||
fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible)
|
|
||||||
fun verifyPrivateTabsCloseTabsButton() = assertPrivateTabsCloseTabsButton()
|
|
||||||
|
|
||||||
fun verifyShareTabsButton(visible: Boolean = true) = assertShareTabsButton(visible)
|
|
||||||
fun verifyCloseTabsButton(title: String) =
|
|
||||||
assertCloseTabsButton(title)
|
|
||||||
|
|
||||||
fun verifyExistingTabList() = assertExistingTabList()
|
|
||||||
fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title)
|
|
||||||
|
|
||||||
fun verifyExistingTopSitesList() = assertExistingTopSitesList()
|
fun verifyExistingTopSitesList() = assertExistingTopSitesList()
|
||||||
fun verifyNotExistingTopSitesList(title: String) = assertNotExistingTopSitesList(title)
|
fun verifyNotExistingTopSitesList(title: String) = assertNotExistingTopSitesList(title)
|
||||||
|
@ -337,8 +320,6 @@ class HomeScreenRobot {
|
||||||
fun swipeTabLeft(title: String) =
|
fun swipeTabLeft(title: String) =
|
||||||
tab(title).perform(ViewActions.swipeLeft())
|
tab(title).perform(ViewActions.swipeLeft())
|
||||||
|
|
||||||
fun closeTabViaXButton(title: String) = closeTabViaX(title)
|
|
||||||
|
|
||||||
fun verifySnackBarText(expectedText: String) {
|
fun verifySnackBarText(expectedText: String) {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
mDevice.waitNotNull(findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
mDevice.waitNotNull(findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
||||||
|
@ -368,6 +349,20 @@ class HomeScreenRobot {
|
||||||
class Transition {
|
class Transition {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
|
||||||
|
fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
||||||
|
mDevice.waitForIdle()
|
||||||
|
|
||||||
|
tabsCounter().click()
|
||||||
|
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
Until.findObject(By.res("org.mozilla.fenix.debug:id/tab_layout")),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
|
|
||||||
|
TabDrawerRobot().interact()
|
||||||
|
return TabDrawerRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
||||||
threeDotButton().perform(click())
|
threeDotButton().perform(click())
|
||||||
|
|
||||||
|
@ -392,7 +387,7 @@ class HomeScreenRobot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
||||||
tabsListThreeDotButton().perform(click())
|
// tabsListThreeDotButton().perform(click())
|
||||||
|
|
||||||
ThreeDotMenuMainRobot().interact()
|
ThreeDotMenuMainRobot().interact()
|
||||||
return ThreeDotMenuMainRobot.Transition()
|
return ThreeDotMenuMainRobot.Transition()
|
||||||
|
@ -510,23 +505,10 @@ private fun assertHomeWordmark() = onView(ViewMatchers.withResourceName("wordmar
|
||||||
private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"))
|
private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertOpenTabsHeader() =
|
private fun assertTabButton() =
|
||||||
onView(allOf(withText("Open tabs")))
|
onView(allOf(withId(R.id.tab_button), isDisplayed()))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertAddTabButton() =
|
|
||||||
onView(allOf(withId(R.id.add_tab_button), isDisplayed()))
|
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
|
||||||
|
|
||||||
private fun assertNoTabsOpenedHeader() =
|
|
||||||
onView(allOf(withText("No open tabs")))
|
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
|
||||||
|
|
||||||
private fun assertNoTabsOpenedText() {
|
|
||||||
onView(allOf(withText("Your open tabs will be shown here.")))
|
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assertCollectionsHeader() =
|
private fun assertCollectionsHeader() =
|
||||||
onView(allOf(withText("Collections")))
|
onView(allOf(withText("Collections")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
@ -535,14 +517,6 @@ private fun assertNoCollectionsHeader() =
|
||||||
onView(allOf(withText("No collections")))
|
onView(allOf(withText("No collections")))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNoCollectionsHeaderIsNotVisible() =
|
|
||||||
onView(allOf(withText("No collections")))
|
|
||||||
.check(doesNotExist())
|
|
||||||
|
|
||||||
private fun assertCollectionsHeaderIsNotVisible() =
|
|
||||||
onView(allOf(withText("Collections")))
|
|
||||||
.check(doesNotExist())
|
|
||||||
|
|
||||||
private fun assertNoCollectionsText() =
|
private fun assertNoCollectionsText() =
|
||||||
onView(
|
onView(
|
||||||
allOf(
|
allOf(
|
||||||
|
@ -551,14 +525,6 @@ private fun assertNoCollectionsText() =
|
||||||
)
|
)
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNoCollectionsTextIsNotVisible() =
|
|
||||||
onView(
|
|
||||||
allOf(
|
|
||||||
withText("Collect the things that matter to you. To start, save open tabs to a new collection.")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.check(doesNotExist())
|
|
||||||
|
|
||||||
private fun assertHomeComponent() =
|
private fun assertHomeComponent() =
|
||||||
onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
|
onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
@ -696,58 +662,16 @@ private fun assertTakePositionBottomRadioButton() =
|
||||||
onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button"))
|
onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
// Private mode elements
|
|
||||||
private fun assertPrivateSessionHeader() =
|
|
||||||
onView(allOf(withText("Private tabs")))
|
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
|
||||||
|
|
||||||
const val PRIVATE_SESSION_MESSAGE =
|
const val PRIVATE_SESSION_MESSAGE =
|
||||||
"Firefox Preview clears your search and browsing history from private tabs when you close them" +
|
"Firefox Preview clears your search and browsing history from private tabs when you close them" +
|
||||||
" or quit the app. While this doesn’t make you anonymous to websites or your internet" +
|
" or quit the app. While this doesn’t make you anonymous to websites or your internet" +
|
||||||
" service provider, it makes it easier to keep what you do online private from anyone" +
|
" service provider, it makes it easier to keep what you do online private from anyone" +
|
||||||
" else who uses this device."
|
" else who uses this device."
|
||||||
|
|
||||||
private fun assertPrivateSessionMessage(visible: Boolean) =
|
private fun assertPrivateSessionMessage() =
|
||||||
onView(withId(R.id.private_session_description))
|
onView(withId(R.id.private_session_description))
|
||||||
.check(
|
|
||||||
if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist()
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun assertShareTabsButton(visible: Boolean) = onView(allOf(withId(R.id.share_tabs_button)))
|
|
||||||
.check(
|
|
||||||
if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else matches(
|
|
||||||
withEffectiveVisibility(Visibility.INVISIBLE)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun assertCloseTabsButton(title: String) =
|
|
||||||
onView(allOf(withId(R.id.close_tab_button), withContentDescription("Close tab $title")))
|
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun visibleOrGone(visibility: Boolean) =
|
|
||||||
if (visibility) Visibility.VISIBLE else Visibility.GONE
|
|
||||||
|
|
||||||
private fun assertExistingTabList() =
|
|
||||||
onView(allOf(withId(R.id.item_tab)))
|
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
|
||||||
|
|
||||||
private fun assertExistingOpenTabs(title: String) {
|
|
||||||
try {
|
|
||||||
tab(title).check(matches(isDisplayed()))
|
|
||||||
} catch (e: NoMatchingViewException) {
|
|
||||||
onView(withId(R.id.sessionControlRecyclerView)).perform(
|
|
||||||
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
|
|
||||||
allOf(
|
|
||||||
withId(R.id.tab_title),
|
|
||||||
withText(title)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tabsListThreeDotButton() = onView(allOf(withId(R.id.tabs_overflow_button)))
|
|
||||||
|
|
||||||
private fun collectionThreeDotButton() =
|
private fun collectionThreeDotButton() =
|
||||||
onView(allOf(withId(R.id.collection_overflow_button)))
|
onView(allOf(withId(R.id.collection_overflow_button)))
|
||||||
|
|
||||||
|
@ -757,18 +681,6 @@ private fun collectionNameTextField() =
|
||||||
private fun collectionTitle(title: String) =
|
private fun collectionTitle(title: String) =
|
||||||
onView(allOf(withId(R.id.collection_title), withText(title)))
|
onView(allOf(withId(R.id.collection_title), withText(title)))
|
||||||
|
|
||||||
private fun closeTabViaX(title: String) {
|
|
||||||
val closeButton = onView(
|
|
||||||
allOf(
|
|
||||||
withId(R.id.close_tab_button),
|
|
||||||
withContentDescription("Close tab $title")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
closeButton.perform(click())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assertPrivateTabsCloseTabsButton() = onView(allOf(withId(R.id.close_tabs_button)))
|
|
||||||
|
|
||||||
private fun assertExistingTopSitesList() =
|
private fun assertExistingTopSitesList() =
|
||||||
onView(allOf(withId(R.id.top_sites_list)))
|
onView(allOf(withId(R.id.top_sites_list)))
|
||||||
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
|
.check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
|
||||||
|
@ -820,6 +732,7 @@ private fun removeTabFromCollectionButton(title: String) =
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun collectionFlowBackButton() = onView(withId(R.id.back_button))
|
private fun collectionFlowBackButton() = onView(withId(R.id.back_button))
|
||||||
|
private fun tabsCounter() = onView(withId(R.id.tab_button))
|
||||||
|
|
||||||
private fun tab(title: String) =
|
private fun tab(title: String) =
|
||||||
onView(
|
onView(
|
||||||
|
|
|
@ -87,7 +87,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
|
||||||
|
|
||||||
fun clickOpenNewTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
fun clickOpenNewTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||||
openInNewTabButton().click()
|
openInNewTabButton().click()
|
||||||
mDevice.waitNotNull(Until.findObject(By.text("Open tabs")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.text("Collections")), waitingTime)
|
||||||
|
|
||||||
HomeScreenRobot().interact()
|
HomeScreenRobot().interact()
|
||||||
return HomeScreenRobot.Transition()
|
return HomeScreenRobot.Transition()
|
||||||
|
@ -96,7 +96,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
|
||||||
fun clickOpenPrivateTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
fun clickOpenPrivateTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||||
openInPrivateTabButton().click()
|
openInPrivateTabButton().click()
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
Until.findObject(By.text("Private tabs")),
|
Until.findObject(By.text(PRIVATE_SESSION_MESSAGE)),
|
||||||
waitingTime
|
waitingTime
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import androidx.test.espresso.action.ViewActions.typeText
|
||||||
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.hasDescendant
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
|
||||||
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.withId
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
@ -100,8 +99,9 @@ class NavigationToolbarRobot {
|
||||||
interact: BrowserRobot.() -> Unit
|
interact: BrowserRobot.() -> Unit
|
||||||
): BrowserRobot.Transition {
|
): BrowserRobot.Transition {
|
||||||
sessionLoadedIdlingResource = SessionLoadedIdlingResource()
|
sessionLoadedIdlingResource = SessionLoadedIdlingResource()
|
||||||
mDevice.waitNotNull(Until.findObject(By.descContains("Add tab")), waitingTime)
|
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")), waitingTime)
|
||||||
newTab().click()
|
|
||||||
|
urlBar().click()
|
||||||
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
||||||
|
|
||||||
runWithIdleRes(sessionLoadedIdlingResource) {
|
runWithIdleRes(sessionLoadedIdlingResource) {
|
||||||
|
@ -181,7 +181,6 @@ private fun dismissOnboardingButton() = onView(withId(R.id.close_onboarding))
|
||||||
private fun urlBar() = onView(withId(R.id.toolbar))
|
private fun urlBar() = onView(withId(R.id.toolbar))
|
||||||
private fun awesomeBar() = onView(withId(R.id.mozac_browser_toolbar_edit_url_view))
|
private fun awesomeBar() = onView(withId(R.id.mozac_browser_toolbar_edit_url_view))
|
||||||
private fun threeDotButton() = onView(withId(R.id.mozac_browser_toolbar_menu))
|
private fun threeDotButton() = onView(withId(R.id.mozac_browser_toolbar_menu))
|
||||||
private fun newTab() = onView(withContentDescription("Add tab"))
|
|
||||||
private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard))
|
private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard))
|
||||||
private fun clearAddressBar() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
|
private fun clearAddressBar() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
|
||||||
private fun goBackButton() = mDevice.pressBack()
|
private fun goBackButton() = mDevice.pressBack()
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/* 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.content.Context
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.espresso.Espresso
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.NoMatchingViewException
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
|
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.By
|
||||||
|
import androidx.test.uiautomator.By.text
|
||||||
|
import androidx.test.uiautomator.UiDevice
|
||||||
|
import androidx.test.uiautomator.Until.findObject
|
||||||
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||||
|
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
||||||
|
import org.mozilla.fenix.helpers.click
|
||||||
|
import org.mozilla.fenix.helpers.ext.waitNotNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of Robot Pattern for the home screen menu.
|
||||||
|
*/
|
||||||
|
class TabDrawerRobot {
|
||||||
|
fun verifyExistingOpenTabs(title: String) = assertExistingOpenTabs(title)
|
||||||
|
fun verifyCloseTabsButton(title: String) = assertCloseTabsButton(title)
|
||||||
|
|
||||||
|
fun verifyExistingTabList() = assertExistingTabList()
|
||||||
|
|
||||||
|
fun verifyNoTabsOpened() = assertNoTabsOpenedText()
|
||||||
|
fun verifyPrivateModeSelected() = assertPrivateModeSelected()
|
||||||
|
fun verifyNormalModeSelected() = assertNormalModeSelected()
|
||||||
|
|
||||||
|
fun closeTab() {
|
||||||
|
closeTabButton().click()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun swipeTabRight(title: String) =
|
||||||
|
tab(title).perform(ViewActions.swipeRight())
|
||||||
|
|
||||||
|
fun swipeTabLeft(title: String) =
|
||||||
|
tab(title).perform(ViewActions.swipeLeft())
|
||||||
|
|
||||||
|
fun closeTabViaXButton(title: String) {
|
||||||
|
val closeButton = onView(
|
||||||
|
allOf(
|
||||||
|
withId(R.id.mozac_browser_tabstray_close),
|
||||||
|
withContentDescription("Close tab $title")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
closeButton.perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifySnackBarText(expectedText: String) {
|
||||||
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
mDevice.waitNotNull(findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun snackBarButtonClick(expectedText: String) {
|
||||||
|
onView(allOf(withId(R.id.snackbar_btn), withText(expectedText))).check(
|
||||||
|
matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))
|
||||||
|
).perform(click())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyTabMediaControlButtonState(action: String) {
|
||||||
|
mDevice.waitNotNull(
|
||||||
|
findObject(
|
||||||
|
By
|
||||||
|
.res("org.mozilla.fenix.debug:id/play_pause_button")
|
||||||
|
.desc(action)
|
||||||
|
),
|
||||||
|
waitingTime
|
||||||
|
)
|
||||||
|
|
||||||
|
tabMediaControlButton().check(matches(withContentDescription(action)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickTabMediaControlButton() = tabMediaControlButton().click()
|
||||||
|
|
||||||
|
class Transition {
|
||||||
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
|
||||||
|
fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
||||||
|
mDevice.waitForIdle()
|
||||||
|
|
||||||
|
Espresso.openActionBarOverflowOrOptionsMenu(ApplicationProvider.getApplicationContext<Context>())
|
||||||
|
ThreeDotMenuMainRobot().interact()
|
||||||
|
return ThreeDotMenuMainRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openHomeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||||
|
mDevice.waitForIdle()
|
||||||
|
|
||||||
|
newTabButton().perform(click())
|
||||||
|
HomeScreenRobot().interact()
|
||||||
|
return HomeScreenRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleToNormalTabs(interact: TabDrawerRobot.() -> Unit): Transition {
|
||||||
|
normalBrowsingButton().perform(click())
|
||||||
|
TabDrawerRobot().interact()
|
||||||
|
return Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleToPrivateTabs(interact: TabDrawerRobot.() -> Unit): Transition {
|
||||||
|
privateBrowsingButton().perform(click())
|
||||||
|
TabDrawerRobot().interact()
|
||||||
|
return Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
||||||
|
threeDotMenu().perform(click())
|
||||||
|
|
||||||
|
ThreeDotMenuMainRobot().interact()
|
||||||
|
return ThreeDotMenuMainRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openTab(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
|
||||||
|
mDevice.waitNotNull(findObject(text(title)))
|
||||||
|
tab(title).click()
|
||||||
|
|
||||||
|
BrowserRobot().interact()
|
||||||
|
return BrowserRobot.Transition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
||||||
|
TabDrawerRobot().interact()
|
||||||
|
return TabDrawerRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tabMediaControlButton() = onView(withId(R.id.play_pause_button))
|
||||||
|
|
||||||
|
private fun closeTabButton() = onView(withId(R.id.mozac_browser_tabstray_close))
|
||||||
|
private fun assertCloseTabsButton(title: String) =
|
||||||
|
onView(allOf(withId(R.id.mozac_browser_tabstray_close), withContentDescription("Close tab $title")))
|
||||||
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun normalBrowsingButton() = onView(withContentDescription("Open tabs"))
|
||||||
|
private fun privateBrowsingButton() = onView(withContentDescription("Private tabs"))
|
||||||
|
private fun newTabButton() = onView(withId(R.id.new_tab_button))
|
||||||
|
private fun threeDotMenu() = onView(withId(R.id.tab_tray_overflow))
|
||||||
|
|
||||||
|
private fun assertExistingOpenTabs(title: String) {
|
||||||
|
try {
|
||||||
|
tab(title).check(matches(isDisplayed()))
|
||||||
|
} catch (e: NoMatchingViewException) {
|
||||||
|
onView(withId(R.id.tabsTray)).perform(
|
||||||
|
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
|
||||||
|
allOf(
|
||||||
|
withId(R.id.mozac_browser_tabstray_title),
|
||||||
|
withText(title)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertExistingTabList() =
|
||||||
|
onView(allOf(withId(R.id.tab_item)))
|
||||||
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun assertNoTabsOpenedText() =
|
||||||
|
onView(withId(R.id.tab_tray_empty_view))
|
||||||
|
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun assertNormalModeSelected() =
|
||||||
|
normalBrowsingButton()
|
||||||
|
.check(matches(ViewMatchers.isSelected()))
|
||||||
|
|
||||||
|
private fun assertPrivateModeSelected() =
|
||||||
|
privateBrowsingButton()
|
||||||
|
.check(matches(ViewMatchers.isSelected()))
|
||||||
|
|
||||||
|
private fun tab(title: String) =
|
||||||
|
onView(
|
||||||
|
allOf(
|
||||||
|
withId(R.id.mozac_browser_tabstray_title),
|
||||||
|
withText(title)
|
||||||
|
)
|
||||||
|
)
|
|
@ -16,6 +16,7 @@ import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.assertion.ViewAssertions
|
import androidx.test.espresso.assertion.ViewAssertions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
|
import androidx.test.espresso.matcher.RootMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
|
@ -186,12 +187,12 @@ class ThreeDotMenuMainRobot {
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeAllTabs(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
fun closeAllTabs(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
||||||
mDevice.waitNotNull(Until.findObject(By.text("Close all tabs")), waitingTime)
|
// mDevice.waitNotNull(Until.findObject(By.text("Close all tabs")), waitingTime)
|
||||||
closeAllTabsButton().click()
|
closeAllTabsButton().click()
|
||||||
|
|
||||||
HomeScreenRobot().interact()
|
TabDrawerRobot().interact()
|
||||||
return HomeScreenRobot.Transition()
|
return TabDrawerRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openFindInPage(interact: FindInPageRobot.() -> Unit): FindInPageRobot.Transition {
|
fun openFindInPage(interact: FindInPageRobot.() -> Unit): FindInPageRobot.Transition {
|
||||||
|
@ -313,11 +314,11 @@ private fun refreshButton() = onView(ViewMatchers.withContentDescription("Refres
|
||||||
private fun assertRefreshButton() = refreshButton()
|
private fun assertRefreshButton() = refreshButton()
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun closeAllTabsButton() = onView(allOf(withText("Close all tabs")))
|
private fun closeAllTabsButton() = onView(allOf(withText("Close all tabs"))).inRoot(RootMatchers.isPlatformPopup())
|
||||||
private fun assertCloseAllTabsButton() = closeAllTabsButton()
|
private fun assertCloseAllTabsButton() = closeAllTabsButton()
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun shareTabButton() = onView(allOf(withText("Share tabs")))
|
private fun shareTabButton() = onView(allOf(withText("Share all tabs"))).inRoot(RootMatchers.isPlatformPopup())
|
||||||
private fun assertShareTabButton() = shareTabButton()
|
private fun assertShareTabButton() = shareTabButton()
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
@ -332,7 +333,7 @@ private fun browserViewSaveCollectionButton() = onView(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun saveCollectionButton() = onView(allOf(withText("Save to collection")))
|
private fun saveCollectionButton() = onView(allOf(withText("Save to collection"))).inRoot(RootMatchers.isPlatformPopup())
|
||||||
private fun assertSaveCollectionButton() = saveCollectionButton()
|
private fun assertSaveCollectionButton() = saveCollectionButton()
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ import androidx.annotation.VisibleForTesting
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import org.mozilla.fenix.components.Analytics
|
import org.mozilla.fenix.components.Analytics
|
||||||
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.home.Tab
|
import org.mozilla.fenix.home.Tab
|
||||||
import org.mozilla.fenix.home.toSessionBundle
|
|
||||||
|
|
||||||
interface CollectionCreationController {
|
interface CollectionCreationController {
|
||||||
|
|
||||||
|
@ -58,6 +58,10 @@ interface CollectionCreationController {
|
||||||
fun removeTabFromSelection(tab: Tab)
|
fun removeTabFromSelection(tab: Tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun List<Tab>.toSessionBundle(sessionManager: SessionManager): List<Session> {
|
||||||
|
return this.mapNotNull { sessionManager.findSessionById(it.sessionId) }
|
||||||
|
}
|
||||||
|
|
||||||
class DefaultCollectionCreationController(
|
class DefaultCollectionCreationController(
|
||||||
private val store: CollectionCreationStore,
|
private val store: CollectionCreationStore,
|
||||||
private val dismiss: () -> Unit,
|
private val dismiss: () -> Unit,
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package org.mozilla.fenix.components
|
package org.mozilla.fenix.components
|
||||||
|
|
||||||
import GeckoProvider
|
import GeckoProvider
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import io.sentry.Sentry
|
import io.sentry.Sentry
|
||||||
|
@ -136,11 +135,6 @@ class Core(private val context: Context) {
|
||||||
*/
|
*/
|
||||||
val customTabsStore by lazy { CustomTabsServiceStore() }
|
val customTabsStore by lazy { CustomTabsServiceStore() }
|
||||||
|
|
||||||
/**
|
|
||||||
* The [PendingSessionDeletionManager] maintains a set of sessionIds that are marked for deletion
|
|
||||||
*/
|
|
||||||
val pendingSessionDeletionManager by lazy { PendingSessionDeletionManager(context as Application) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The session manager component provides access to a centralized registry of
|
* The session manager component provides access to a centralized registry of
|
||||||
* all browser sessions (i.e. tabs). It is initialized here to persist and restore
|
* all browser sessions (i.e. tabs). It is initialized here to persist and restore
|
||||||
|
@ -173,12 +167,6 @@ class Core(private val context: Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingSessionDeletionManager.getSessionsToDelete(context).forEach {
|
|
||||||
sessionManager.findSessionById(it)?.let { session ->
|
|
||||||
sessionManager.remove(session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we have restored our previous state (if there's one) let's setup auto saving the state while
|
// Now that we have restored our previous state (if there's one) let's setup auto saving the state while
|
||||||
// the app is used.
|
// the app is used.
|
||||||
sessionStorage.autoSave(sessionManager)
|
sessionStorage.autoSave(sessionManager)
|
||||||
|
|
|
@ -1,71 +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
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
|
|
||||||
class PendingSessionDeletionManager(application: Application) :
|
|
||||||
Application.ActivityLifecycleCallbacks {
|
|
||||||
|
|
||||||
private val sessionIdsPendingDeletion = mutableSetOf<String>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
application.registerActivityLifecycleCallbacks(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addSession(sessionId: String) {
|
|
||||||
sessionIdsPendingDeletion.add(sessionId)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeSession(sessionId: String) {
|
|
||||||
sessionIdsPendingDeletion.remove(sessionId)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSessionsToDelete(context: Context): Set<String> {
|
|
||||||
return context.settings().preferences.getStringSet(
|
|
||||||
PREF_KEY,
|
|
||||||
setOf()
|
|
||||||
) ?: setOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityPaused(activity: Activity?) {
|
|
||||||
activity?.settings()?.preferences?.edit()?.putStringSet(
|
|
||||||
PREF_KEY,
|
|
||||||
sessionIdsPendingDeletion
|
|
||||||
)?.apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResumed(p0: Activity?) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityStarted(p0: Activity?) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityDestroyed(p0: Activity?) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivitySaveInstanceState(p0: Activity?, p1: Bundle?) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityStopped(p0: Activity?) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(p0: Activity?, p1: Bundle?) {
|
|
||||||
/* no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val PREF_KEY = "pref_key_session_id_set_to_delete"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,7 +14,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
|
@ -122,8 +121,7 @@ class DefaultBrowserToolbarController(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleTabCounterClick() {
|
override fun handleTabCounterClick() {
|
||||||
sharedViewModel.shouldScrollToSelectedTab = true
|
onTabCounterClicked.invoke()
|
||||||
animateTabAndNavigateHome()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleBrowserMenuDismissed(lowPrioHighlightItems: List<ToolbarMenu.Item>) {
|
override fun handleBrowserMenuDismissed(lowPrioHighlightItems: List<ToolbarMenu.Item>) {
|
||||||
|
@ -132,7 +130,8 @@ class DefaultBrowserToolbarController(
|
||||||
ToolbarMenu.Item.AddToHomeScreen -> activity.settings().installPwaOpened = true
|
ToolbarMenu.Item.AddToHomeScreen -> activity.settings().installPwaOpened = true
|
||||||
is ToolbarMenu.Item.ReaderMode -> activity.settings().readerModeOpened = true
|
is ToolbarMenu.Item.ReaderMode -> activity.settings().readerModeOpened = true
|
||||||
ToolbarMenu.Item.OpenInApp -> activity.settings().openInAppOpened = true
|
ToolbarMenu.Item.OpenInApp -> activity.settings().openInAppOpened = true
|
||||||
else -> { }
|
else -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +157,9 @@ class DefaultBrowserToolbarController(
|
||||||
}
|
}
|
||||||
ToolbarMenu.Item.SyncedTabs -> {
|
ToolbarMenu.Item.SyncedTabs -> {
|
||||||
navController.nav(
|
navController.nav(
|
||||||
R.id.browserFragment, BrowserFragmentDirections.actionBrowserFragmentToSyncedTabsFragment())
|
R.id.browserFragment,
|
||||||
|
BrowserFragmentDirections.actionBrowserFragmentToSyncedTabsFragment()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is ToolbarMenu.Item.RequestDesktop -> sessionUseCases.requestDesktopSite.invoke(
|
is ToolbarMenu.Item.RequestDesktop -> sessionUseCases.requestDesktopSite.invoke(
|
||||||
item.isChecked,
|
item.isChecked,
|
||||||
|
@ -315,23 +316,11 @@ class DefaultBrowserToolbarController(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun animateTabAndNavigateHome() {
|
private fun reportSiteIssue(reportUrl: String, private: Boolean) {
|
||||||
if (activity.settings().useNewTabTray) {
|
if (private) {
|
||||||
onTabCounterClicked.invoke()
|
activity.components.useCases.tabsUseCases.addPrivateTab.invoke(reportUrl)
|
||||||
return
|
} else {
|
||||||
}
|
activity.components.useCases.tabsUseCases.addTab.invoke(reportUrl)
|
||||||
|
|
||||||
scope.launch {
|
|
||||||
browserAnimator.beginAnimateOut()
|
|
||||||
// Delay for a short amount of time so the browser has time to start animating out
|
|
||||||
// before we transition the fragment. This makes the animation feel smoother
|
|
||||||
delay(ANIMATION_DELAY)
|
|
||||||
if (!navController.popBackStack(R.id.homeFragment, false)) {
|
|
||||||
navController.nav(
|
|
||||||
R.id.browserFragment,
|
|
||||||
BrowserFragmentDirections.actionGlobalHome()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,11 @@ import androidx.constraintlayout.widget.ConstraintSet.TOP
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.doOnLayout
|
import androidx.core.view.doOnLayout
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleObserver
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.OnLifecycleEvent
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
@ -46,34 +42,27 @@ import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
import kotlinx.android.synthetic.main.fragment_home.view.*
|
import kotlinx.android.synthetic.main.fragment_home.view.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.browser.menu.view.MenuButton
|
import mozilla.components.browser.menu.view.MenuButton
|
||||||
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.browser.state.state.MediaState.State.PLAYING
|
import mozilla.components.browser.state.selector.normalTabs
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
import mozilla.components.browser.state.selector.privateTabs
|
||||||
import mozilla.components.concept.sync.AccountObserver
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
import mozilla.components.concept.sync.AuthType
|
import mozilla.components.concept.sync.AuthType
|
||||||
import mozilla.components.concept.sync.OAuthAccount
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
import mozilla.components.feature.media.ext.pauseIfPlaying
|
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
import mozilla.components.lib.state.ext.consumeFrom
|
import mozilla.components.lib.state.ext.consumeFrom
|
||||||
import mozilla.components.lib.state.ext.flowScoped
|
|
||||||
import mozilla.components.support.ktx.android.util.dpToPx
|
import mozilla.components.support.ktx.android.util.dpToPx
|
||||||
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged
|
|
||||||
import org.mozilla.fenix.BrowserDirection
|
import org.mozilla.fenix.BrowserDirection
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.addons.runIfFragmentIsAttached
|
|
||||||
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
|
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.cfr.SearchWidgetCFR
|
import org.mozilla.fenix.cfr.SearchWidgetCFR
|
||||||
|
@ -92,9 +81,7 @@ 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.ext.toTab
|
import org.mozilla.fenix.ext.toTab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.AdapterItem
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.DefaultSessionControlController
|
import org.mozilla.fenix.home.sessioncontrol.DefaultSessionControlController
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlAdapter
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlView
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlView
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
||||||
|
@ -106,7 +93,6 @@ import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
|
||||||
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
|
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
import org.mozilla.fenix.utils.FragmentPreDrawManager
|
import org.mozilla.fenix.utils.FragmentPreDrawManager
|
||||||
import org.mozilla.fenix.utils.allowUndo
|
|
||||||
import org.mozilla.fenix.whatsnew.WhatsNew
|
import org.mozilla.fenix.whatsnew.WhatsNew
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
@ -118,8 +104,6 @@ class HomeFragment : Fragment() {
|
||||||
ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
|
ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sharedViewModel: SharedViewModel by activityViewModels()
|
|
||||||
|
|
||||||
private val snackbarAnchorView: View?
|
private val snackbarAnchorView: View?
|
||||||
get() {
|
get() {
|
||||||
return if (requireContext().settings().shouldUseBottomToolbar) {
|
return if (requireContext().settings().shouldUseBottomToolbar) {
|
||||||
|
@ -131,11 +115,6 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager
|
private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager
|
||||||
private var homeAppBarOffset = 0
|
private var homeAppBarOffset = 0
|
||||||
private val singleSessionObserver = object : Session.Observer {
|
|
||||||
override fun onTitleChanged(session: Session, title: String) {
|
|
||||||
if (deleteAllSessionsJob == null) emitSessionChanges()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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>) {
|
||||||
|
@ -154,11 +133,6 @@ class HomeFragment : Fragment() {
|
||||||
private val sessionManager: SessionManager
|
private val sessionManager: SessionManager
|
||||||
get() = requireComponents.core.sessionManager
|
get() = requireComponents.core.sessionManager
|
||||||
|
|
||||||
var deleteAllSessionsJob: (suspend () -> Unit)? = null
|
|
||||||
private var pendingSessionDeletion: PendingSessionDeletion? = null
|
|
||||||
|
|
||||||
data class PendingSessionDeletion(val deletionJob: (suspend () -> Unit), val sessionId: String)
|
|
||||||
|
|
||||||
private lateinit var homeAppBarOffSetListener: AppBarLayout.OnOffsetChangedListener
|
private lateinit var homeAppBarOffSetListener: AppBarLayout.OnOffsetChangedListener
|
||||||
private val onboarding by lazy { FenixOnboarding(requireContext()) }
|
private val onboarding by lazy { FenixOnboarding(requireContext()) }
|
||||||
private lateinit var homeFragmentStore: HomeFragmentStore
|
private lateinit var homeFragmentStore: HomeFragmentStore
|
||||||
|
@ -185,16 +159,6 @@ class HomeFragment : Fragment() {
|
||||||
val view = inflater.inflate(R.layout.fragment_home, container, false)
|
val view = inflater.inflate(R.layout.fragment_home, container, false)
|
||||||
val activity = activity as HomeActivity
|
val activity = activity as HomeActivity
|
||||||
|
|
||||||
val sessionObserver = BrowserSessionsObserver(
|
|
||||||
sessionManager,
|
|
||||||
requireComponents.core.store,
|
|
||||||
singleSessionObserver
|
|
||||||
) {
|
|
||||||
emitSessionChanges()
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycle.addObserver(sessionObserver)
|
|
||||||
|
|
||||||
currentMode = CurrentMode(
|
currentMode = CurrentMode(
|
||||||
view.context,
|
view.context,
|
||||||
onboarding,
|
onboarding,
|
||||||
|
@ -208,7 +172,6 @@ class HomeFragment : Fragment() {
|
||||||
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections,
|
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections,
|
||||||
expandedCollections = emptySet(),
|
expandedCollections = emptySet(),
|
||||||
mode = currentMode.getCurrentMode(),
|
mode = currentMode.getCurrentMode(),
|
||||||
tabs = emptyList(),
|
|
||||||
topSites = requireComponents.core.topSiteStorage.cachedTopSites,
|
topSites = requireComponents.core.topSiteStorage.cachedTopSites,
|
||||||
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
|
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
|
||||||
)
|
)
|
||||||
|
@ -217,22 +180,15 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
_sessionControlInteractor = SessionControlInteractor(
|
_sessionControlInteractor = SessionControlInteractor(
|
||||||
DefaultSessionControlController(
|
DefaultSessionControlController(
|
||||||
store = requireComponents.core.store,
|
|
||||||
activity = activity,
|
activity = activity,
|
||||||
fragmentStore = homeFragmentStore,
|
fragmentStore = homeFragmentStore,
|
||||||
navController = findNavController(),
|
navController = findNavController(),
|
||||||
browsingModeManager = browsingModeManager,
|
|
||||||
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
|
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
|
||||||
closeTab = ::closeTab,
|
|
||||||
closeAllTabs = ::closeAllTabs,
|
|
||||||
getListOfTabs = ::getListOfTabs,
|
getListOfTabs = ::getListOfTabs,
|
||||||
hideOnboarding = ::hideOnboardingAndOpenSearch,
|
hideOnboarding = ::hideOnboardingAndOpenSearch,
|
||||||
invokePendingDeleteJobs = ::invokePendingDeleteJobs,
|
|
||||||
registerCollectionStorageObserver = ::registerCollectionStorageObserver,
|
registerCollectionStorageObserver = ::registerCollectionStorageObserver,
|
||||||
scrollToTheTop = ::scrollToTheTop,
|
|
||||||
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
|
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
|
||||||
openSettingsScreen = ::openSettingsScreen,
|
openSettingsScreen = ::openSettingsScreen,
|
||||||
openSearchScreen = ::navigateToSearch,
|
|
||||||
openWhatsNewLink = { openInNormalTab(SupportUtils.getWhatsNewUrl(activity)) },
|
openWhatsNewLink = { openInNormalTab(SupportUtils.getWhatsNewUrl(activity)) },
|
||||||
openPrivacyNotice = { openInNormalTab(SupportUtils.getMozillaPageUrl(PRIVATE_NOTICE)) },
|
openPrivacyNotice = { openInNormalTab(SupportUtils.getMozillaPageUrl(PRIVATE_NOTICE)) },
|
||||||
showTabTray = ::openTabTray
|
showTabTray = ::openTabTray
|
||||||
|
@ -249,10 +205,16 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
view.consumeFrom(homeFragmentStore, viewLifecycleOwner) {
|
view.consumeFrom(homeFragmentStore, viewLifecycleOwner) {
|
||||||
sessionControlView?.update(it)
|
sessionControlView?.update(it)
|
||||||
|
}
|
||||||
|
|
||||||
if (context?.settings()?.useNewTabTray == true) {
|
view.consumeFrom(requireComponents.core.store, viewLifecycleOwner) {
|
||||||
view.tab_button.setCountWithAnimation(it.tabs.size)
|
val tabCount = if (currentMode.getCurrentMode() == Mode.Normal) {
|
||||||
|
it.normalTabs.size
|
||||||
|
} else {
|
||||||
|
it.privateTabs.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
view.tab_button.setCountWithAnimation(tabCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
@ -263,9 +225,9 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
if (!shouldUseBottomToolbar) {
|
if (!shouldUseBottomToolbar) {
|
||||||
view.toolbarLayout.layoutParams = CoordinatorLayout.LayoutParams(
|
view.toolbarLayout.layoutParams = CoordinatorLayout.LayoutParams(
|
||||||
ConstraintLayout.LayoutParams.MATCH_PARENT,
|
ConstraintLayout.LayoutParams.MATCH_PARENT,
|
||||||
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
||||||
)
|
)
|
||||||
.apply {
|
.apply {
|
||||||
gravity = Gravity.TOP
|
gravity = Gravity.TOP
|
||||||
}
|
}
|
||||||
|
@ -339,26 +301,21 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
createHomeMenu(requireContext(), WeakReference(view.menuButton))
|
createHomeMenu(requireContext(), WeakReference(view.menuButton))
|
||||||
|
|
||||||
view.menuButton.setColorFilter(ContextCompat.getColor(
|
view.menuButton.setColorFilter(
|
||||||
requireContext(),
|
ContextCompat.getColor(
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, requireContext())
|
requireContext(),
|
||||||
))
|
ThemeManager.resolveAttribute(R.attr.primaryText, requireContext())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
view.toolbar.compoundDrawablePadding =
|
view.toolbar.compoundDrawablePadding =
|
||||||
view.resources.getDimensionPixelSize(R.dimen.search_bar_search_engine_icon_padding)
|
view.resources.getDimensionPixelSize(R.dimen.search_bar_search_engine_icon_padding)
|
||||||
view.toolbar_wrapper.setOnClickListener {
|
view.toolbar_wrapper.setOnClickListener {
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
hideOnboardingIfNeeded()
|
||||||
navigateToSearch()
|
navigateToSearch()
|
||||||
requireComponents.analytics.metrics.track(Event.SearchBarTapped(Event.SearchBarTapped.Source.HOME))
|
requireComponents.analytics.metrics.track(Event.SearchBarTapped(Event.SearchBarTapped.Source.HOME))
|
||||||
}
|
}
|
||||||
|
|
||||||
view.add_tab_button.setOnClickListener {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
navigateToSearch()
|
|
||||||
}
|
|
||||||
|
|
||||||
view.tab_button.setOnClickListener {
|
view.tab_button.setOnClickListener {
|
||||||
openTabTray()
|
openTabTray()
|
||||||
}
|
}
|
||||||
|
@ -367,8 +324,6 @@ class HomeFragment : Fragment() {
|
||||||
privateBrowsingButton,
|
privateBrowsingButton,
|
||||||
browsingModeManager
|
browsingModeManager
|
||||||
) { newMode ->
|
) { newMode ->
|
||||||
invokePendingDeleteJobs()
|
|
||||||
|
|
||||||
if (newMode == BrowsingMode.Private) {
|
if (newMode == BrowsingMode.Private) {
|
||||||
requireContext().settings().incrementNumTimesPrivateModeOpened()
|
requireContext().settings().incrementNumTimesPrivateModeOpened()
|
||||||
}
|
}
|
||||||
|
@ -408,7 +363,6 @@ class HomeFragment : Fragment() {
|
||||||
HomeFragmentAction.Change(
|
HomeFragmentAction.Change(
|
||||||
collections = components.core.tabCollectionStorage.cachedTabCollections,
|
collections = components.core.tabCollectionStorage.cachedTabCollections,
|
||||||
mode = currentMode.getCurrentMode(),
|
mode = currentMode.getCurrentMode(),
|
||||||
tabs = getListOfSessions().toTabs(),
|
|
||||||
topSites = components.core.topSiteStorage.cachedTopSites,
|
topSites = components.core.topSiteStorage.cachedTopSites,
|
||||||
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
|
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
|
||||||
)
|
)
|
||||||
|
@ -428,7 +382,8 @@ class HomeFragment : Fragment() {
|
||||||
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
||||||
if (authType != AuthType.Existing) {
|
if (authType != AuthType.Existing) {
|
||||||
view?.let {
|
view?.let {
|
||||||
FenixSnackbar.make(view = it,
|
FenixSnackbar.make(
|
||||||
|
view = it,
|
||||||
duration = Snackbar.LENGTH_SHORT,
|
duration = Snackbar.LENGTH_SHORT,
|
||||||
isDisplayedWithBrowserToolbar = false
|
isDisplayedWithBrowserToolbar = false
|
||||||
)
|
)
|
||||||
|
@ -451,79 +406,12 @@ class HomeFragment : Fragment() {
|
||||||
requireComponents.core.tabCollectionStorage.unregister(collectionStorageObserver)
|
requireComponents.core.tabCollectionStorage.unregister(collectionStorageObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun closeTab(sessionId: String) {
|
|
||||||
val deletionJob = pendingSessionDeletion?.deletionJob
|
|
||||||
context?.let {
|
|
||||||
if (sessionManager.findSessionById(sessionId)?.toTab(it)?.mediaState == PLAYING) {
|
|
||||||
it.components.core.store.state.media.pauseIfPlaying()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deletionJob == null) {
|
|
||||||
removeTabWithUndo(sessionId, browsingModeManager.mode.isPrivate)
|
|
||||||
} else {
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
deletionJob.invoke()
|
|
||||||
}.invokeOnCompletion {
|
|
||||||
pendingSessionDeletion = null
|
|
||||||
removeTabWithUndo(sessionId, browsingModeManager.mode.isPrivate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun closeAllTabs(isPrivateMode: Boolean) {
|
|
||||||
val deletionJob = pendingSessionDeletion?.deletionJob
|
|
||||||
|
|
||||||
context?.let {
|
|
||||||
sessionManager.sessionsOfType(private = isPrivateMode).forEach { session ->
|
|
||||||
if (session.toTab(it).mediaState == PLAYING) {
|
|
||||||
it.components.core.store.state.media.pauseIfPlaying()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deletionJob == null) {
|
|
||||||
removeAllTabsWithUndo(
|
|
||||||
sessionManager.sessionsOfType(private = isPrivateMode),
|
|
||||||
isPrivateMode
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
deletionJob.invoke()
|
|
||||||
}.invokeOnCompletion {
|
|
||||||
pendingSessionDeletion = null
|
|
||||||
removeAllTabsWithUndo(
|
|
||||||
sessionManager.sessionsOfType(private = isPrivateMode),
|
|
||||||
isPrivateMode
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dispatchModeChanges(mode: Mode) {
|
private fun dispatchModeChanges(mode: Mode) {
|
||||||
if (mode != Mode.fromBrowsingMode(browsingModeManager.mode)) {
|
if (mode != Mode.fromBrowsingMode(browsingModeManager.mode)) {
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(mode))
|
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invokePendingDeleteJobs() {
|
|
||||||
pendingSessionDeletion?.deletionJob?.let {
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
it.invoke()
|
|
||||||
}.invokeOnCompletion {
|
|
||||||
pendingSessionDeletion = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteAllSessionsJob?.let {
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
it.invoke()
|
|
||||||
}.invokeOnCompletion {
|
|
||||||
deleteAllSessionsJob = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showDeleteCollectionPrompt(tabCollection: TabCollection) {
|
private fun showDeleteCollectionPrompt(tabCollection: TabCollection) {
|
||||||
val context = context ?: return
|
val context = context ?: return
|
||||||
AlertDialog.Builder(context).apply {
|
AlertDialog.Builder(context).apply {
|
||||||
|
@ -546,7 +434,6 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
invokePendingDeleteJobs()
|
|
||||||
super.onStop()
|
super.onStop()
|
||||||
val homeViewModel: HomeScreenViewModel by activityViewModels {
|
val homeViewModel: HomeScreenViewModel by activityViewModels {
|
||||||
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
|
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
|
||||||
|
@ -561,17 +448,6 @@ class HomeFragment : Fragment() {
|
||||||
activity?.window?.setBackgroundDrawableResource(R.drawable.private_home_background_gradient)
|
activity?.window?.setBackgroundDrawableResource(R.drawable.private_home_background_gradient)
|
||||||
}
|
}
|
||||||
hideToolbar()
|
hideToolbar()
|
||||||
if (sharedViewModel.shouldScrollToSelectedTab) {
|
|
||||||
scrollToSelectedTab()
|
|
||||||
sharedViewModel.shouldScrollToSelectedTab = false
|
|
||||||
}
|
|
||||||
|
|
||||||
requireContext().settings().useNewTabTray.also {
|
|
||||||
view?.add_tab_button?.isVisible = !it
|
|
||||||
view?.tab_button?.isVisible = it
|
|
||||||
// Scrolls to the top of the screen
|
|
||||||
view?.homeAppBar?.setExpanded(true, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
@ -631,8 +507,7 @@ class HomeFragment : Fragment() {
|
||||||
onboarding.finish()
|
onboarding.finish()
|
||||||
homeFragmentStore.dispatch(
|
homeFragmentStore.dispatch(
|
||||||
HomeFragmentAction.ModeChange(
|
HomeFragmentAction.ModeChange(
|
||||||
mode = currentMode.getCurrentMode(),
|
mode = currentMode.getCurrentMode()
|
||||||
tabs = getListOfSessions().toTabs()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -665,96 +540,91 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ComplexMethod", "LongMethod")
|
@SuppressWarnings("ComplexMethod", "LongMethod")
|
||||||
private fun createHomeMenu(context: Context, menuButtonView: WeakReference<MenuButton>) = HomeMenu(
|
private fun createHomeMenu(context: Context, menuButtonView: WeakReference<MenuButton>) =
|
||||||
this.viewLifecycleOwner,
|
HomeMenu(
|
||||||
context,
|
this.viewLifecycleOwner,
|
||||||
onItemTapped = {
|
context,
|
||||||
when (it) {
|
onItemTapped = {
|
||||||
HomeMenu.Item.Settings -> {
|
when (it) {
|
||||||
invokePendingDeleteJobs()
|
HomeMenu.Item.Settings -> {
|
||||||
hideOnboardingIfNeeded()
|
hideOnboardingIfNeeded()
|
||||||
nav(
|
nav(
|
||||||
R.id.homeFragment,
|
R.id.homeFragment,
|
||||||
HomeFragmentDirections.actionGlobalSettingsFragment()
|
HomeFragmentDirections.actionGlobalSettingsFragment()
|
||||||
)
|
|
||||||
}
|
|
||||||
HomeMenu.Item.SyncedTabs -> {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
nav(
|
|
||||||
R.id.homeFragment,
|
|
||||||
HomeFragmentDirections.actionGlobalSyncedTabsFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
HomeMenu.Item.Bookmarks -> {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
nav(
|
|
||||||
R.id.homeFragment,
|
|
||||||
HomeFragmentDirections.actionGlobalBookmarkFragment(BookmarkRoot.Mobile.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
HomeMenu.Item.History -> {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
nav(
|
|
||||||
R.id.homeFragment,
|
|
||||||
HomeFragmentDirections.actionGlobalHistoryFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
HomeMenu.Item.Help -> {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
(activity as HomeActivity).openToBrowserAndLoad(
|
|
||||||
searchTermOrURL = SupportUtils.getSumoURLForTopic(context, HELP),
|
|
||||||
newTab = true,
|
|
||||||
from = BrowserDirection.FromHome
|
|
||||||
)
|
|
||||||
}
|
|
||||||
HomeMenu.Item.WhatsNew -> {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
WhatsNew.userViewedWhatsNew(context)
|
|
||||||
context.metrics.track(Event.WhatsNewTapped)
|
|
||||||
(activity as HomeActivity).openToBrowserAndLoad(
|
|
||||||
searchTermOrURL = SupportUtils.getWhatsNewUrl(context),
|
|
||||||
newTab = true,
|
|
||||||
from = BrowserDirection.FromHome
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// We need to show the snackbar while the browsing data is deleting(if "Delete
|
|
||||||
// browsing data on quit" is activated). After the deletion is over, the snackbar
|
|
||||||
// is dismissed.
|
|
||||||
HomeMenu.Item.Quit -> activity?.let { activity ->
|
|
||||||
deleteAndQuit(
|
|
||||||
activity,
|
|
||||||
viewLifecycleOwner.lifecycleScope,
|
|
||||||
view?.let { view -> FenixSnackbar.make(
|
|
||||||
view = view,
|
|
||||||
isDisplayedWithBrowserToolbar = false
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
HomeMenu.Item.SyncedTabs -> {
|
||||||
|
hideOnboardingIfNeeded()
|
||||||
|
nav(
|
||||||
|
R.id.homeFragment,
|
||||||
|
HomeFragmentDirections.actionGlobalSyncedTabsFragment()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HomeMenu.Item.Bookmarks -> {
|
||||||
|
hideOnboardingIfNeeded()
|
||||||
|
nav(
|
||||||
|
R.id.homeFragment,
|
||||||
|
HomeFragmentDirections.actionGlobalBookmarkFragment(BookmarkRoot.Mobile.id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HomeMenu.Item.History -> {
|
||||||
|
hideOnboardingIfNeeded()
|
||||||
|
nav(
|
||||||
|
R.id.homeFragment,
|
||||||
|
HomeFragmentDirections.actionGlobalHistoryFragment()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HomeMenu.Item.Help -> {
|
||||||
|
hideOnboardingIfNeeded()
|
||||||
|
(activity as HomeActivity).openToBrowserAndLoad(
|
||||||
|
searchTermOrURL = SupportUtils.getSumoURLForTopic(context, HELP),
|
||||||
|
newTab = true,
|
||||||
|
from = BrowserDirection.FromHome
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HomeMenu.Item.WhatsNew -> {
|
||||||
|
hideOnboardingIfNeeded()
|
||||||
|
WhatsNew.userViewedWhatsNew(context)
|
||||||
|
context.metrics.track(Event.WhatsNewTapped)
|
||||||
|
(activity as HomeActivity).openToBrowserAndLoad(
|
||||||
|
searchTermOrURL = SupportUtils.getWhatsNewUrl(context),
|
||||||
|
newTab = true,
|
||||||
|
from = BrowserDirection.FromHome
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// We need to show the snackbar while the browsing data is deleting(if "Delete
|
||||||
|
// browsing data on quit" is activated). After the deletion is over, the snackbar
|
||||||
|
// is dismissed.
|
||||||
|
HomeMenu.Item.Quit -> activity?.let { activity ->
|
||||||
|
deleteAndQuit(
|
||||||
|
activity,
|
||||||
|
viewLifecycleOwner.lifecycleScope,
|
||||||
|
view?.let { view ->
|
||||||
|
FenixSnackbar.make(
|
||||||
|
view = view,
|
||||||
|
isDisplayedWithBrowserToolbar = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HomeMenu.Item.Sync -> {
|
||||||
|
hideOnboardingIfNeeded()
|
||||||
|
nav(
|
||||||
|
R.id.homeFragment,
|
||||||
|
HomeFragmentDirections.actionGlobalAccountProblemFragment()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HomeMenu.Item.AddonsManager -> {
|
||||||
|
nav(
|
||||||
|
R.id.homeFragment,
|
||||||
|
HomeFragmentDirections.actionGlobalAddonsManagementFragment()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
HomeMenu.Item.Sync -> {
|
},
|
||||||
invokePendingDeleteJobs()
|
onHighlightPresent = { menuButtonView.get()?.setHighlight(it) },
|
||||||
hideOnboardingIfNeeded()
|
onMenuBuilderChanged = { menuButtonView.get()?.menuBuilder = it }
|
||||||
nav(
|
)
|
||||||
R.id.homeFragment,
|
|
||||||
HomeFragmentDirections.actionGlobalAccountProblemFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
HomeMenu.Item.AddonsManager -> {
|
|
||||||
nav(
|
|
||||||
R.id.homeFragment,
|
|
||||||
HomeFragmentDirections.actionGlobalAddonsManagementFragment()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onHighlightPresent = { menuButtonView.get()?.setHighlight(it) },
|
|
||||||
onMenuBuilderChanged = { menuButtonView.get()?.menuBuilder = it }
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun subscribeToTabCollections(): Observer<List<TabCollection>> {
|
private fun subscribeToTabCollections(): Observer<List<TabCollection>> {
|
||||||
return Observer<List<TabCollection>> {
|
return Observer<List<TabCollection>> {
|
||||||
|
@ -776,93 +646,8 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAllTabsWithUndo(listOfSessionsToDelete: Sequence<Session>, private: Boolean) {
|
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(emptyList()))
|
|
||||||
listOfSessionsToDelete.forEach {
|
|
||||||
requireComponents.core.pendingSessionDeletionManager.addSession(
|
|
||||||
it.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val deleteOperation: (suspend () -> Unit) = {
|
|
||||||
listOfSessionsToDelete.forEach {
|
|
||||||
sessionManager.remove(it)
|
|
||||||
requireComponents.core.pendingSessionDeletionManager.removeSession(it.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deleteAllSessionsJob = deleteOperation
|
|
||||||
|
|
||||||
val snackbarMessage = if (private) {
|
|
||||||
getString(R.string.snackbar_private_tabs_closed)
|
|
||||||
} else {
|
|
||||||
getString(R.string.snackbar_tabs_closed)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.allowUndo(
|
|
||||||
requireView(),
|
|
||||||
snackbarMessage,
|
|
||||||
getString(R.string.snackbar_deleted_undo), {
|
|
||||||
listOfSessionsToDelete.forEach {
|
|
||||||
requireComponents.core.pendingSessionDeletionManager.removeSession(
|
|
||||||
it.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (private) {
|
|
||||||
requireComponents.analytics.metrics.track(Event.PrivateBrowsingSnackbarUndoTapped)
|
|
||||||
}
|
|
||||||
deleteAllSessionsJob = null
|
|
||||||
emitSessionChanges()
|
|
||||||
},
|
|
||||||
operation = deleteOperation,
|
|
||||||
anchorView = snackbarAnchorView
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removeTabWithUndo(sessionId: String, private: Boolean) {
|
|
||||||
val sessionManager = requireComponents.core.sessionManager
|
|
||||||
requireComponents.core.pendingSessionDeletionManager.addSession(sessionId)
|
|
||||||
val deleteOperation: (suspend () -> Unit) = {
|
|
||||||
sessionManager.findSessionById(sessionId)
|
|
||||||
?.let { session ->
|
|
||||||
pendingSessionDeletion = null
|
|
||||||
sessionManager.remove(session)
|
|
||||||
requireComponents.core.pendingSessionDeletionManager.removeSession(sessionId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingSessionDeletion = PendingSessionDeletion(deleteOperation, sessionId)
|
|
||||||
|
|
||||||
val snackbarMessage = if (private) {
|
|
||||||
getString(R.string.snackbar_private_tab_closed)
|
|
||||||
} else {
|
|
||||||
getString(R.string.snackbar_tab_closed)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.allowUndo(
|
|
||||||
requireView(),
|
|
||||||
snackbarMessage,
|
|
||||||
getString(R.string.snackbar_deleted_undo), {
|
|
||||||
requireComponents.core.pendingSessionDeletionManager.removeSession(sessionId)
|
|
||||||
pendingSessionDeletion = null
|
|
||||||
emitSessionChanges()
|
|
||||||
},
|
|
||||||
operation = deleteOperation,
|
|
||||||
anchorView = snackbarAnchorView
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update the UI with the tab removed, but don't remove it from storage yet
|
|
||||||
emitSessionChanges()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun emitSessionChanges() {
|
|
||||||
runIfFragmentIsAttached {
|
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(getListOfTabs()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getListOfSessions(private: Boolean = browsingModeManager.mode.isPrivate): List<Session> {
|
private fun getListOfSessions(private: Boolean = browsingModeManager.mode.isPrivate): List<Session> {
|
||||||
return sessionManager.sessionsOfType(private = private)
|
return sessionManager.sessionsOfType(private = private)
|
||||||
.filter { session: Session -> session.id != pendingSessionDeletion?.sessionId }
|
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,13 +659,6 @@ class HomeFragment : Fragment() {
|
||||||
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToTheTop() {
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch(Main) {
|
|
||||||
delay(ANIM_SCROLL_DELAY)
|
|
||||||
sessionControlView!!.view.smoothScrollToPosition(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scrollAndAnimateCollection(
|
private fun scrollAndAnimateCollection(
|
||||||
tabsAddedToCollectionSize: Int,
|
tabsAddedToCollectionSize: Int,
|
||||||
changedCollection: TabCollection? = null
|
changedCollection: TabCollection? = null
|
||||||
|
@ -968,7 +746,8 @@ class HomeFragment : Fragment() {
|
||||||
} else {
|
} else {
|
||||||
R.string.create_collection_tab_saved
|
R.string.create_collection_tab_saved
|
||||||
}
|
}
|
||||||
FenixSnackbar.make(view = view,
|
FenixSnackbar.make(
|
||||||
|
view = view,
|
||||||
duration = Snackbar.LENGTH_LONG,
|
duration = Snackbar.LENGTH_LONG,
|
||||||
isDisplayedWithBrowserToolbar = false
|
isDisplayedWithBrowserToolbar = false
|
||||||
)
|
)
|
||||||
|
@ -1025,20 +804,7 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToSelectedTab() {
|
|
||||||
val position = (sessionControlView!!.view.adapter as SessionControlAdapter)
|
|
||||||
.currentList.indexOfFirst {
|
|
||||||
it is AdapterItem.TabItem && it.tab.selected == true
|
|
||||||
}
|
|
||||||
if (position > 0) {
|
|
||||||
(sessionControlView!!.view.layoutManager as LinearLayoutManager)
|
|
||||||
.scrollToPositionWithOffset(position, SELECTED_TAB_OFFSET)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openTabTray() {
|
private fun openTabTray() {
|
||||||
invokePendingDeleteJobs()
|
|
||||||
hideOnboardingIfNeeded()
|
|
||||||
TabTrayDialogFragment.show(parentFragmentManager)
|
TabTrayDialogFragment.show(parentFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,97 +818,8 @@ class HomeFragment : Fragment() {
|
||||||
private const val ANIM_SNACKBAR_DELAY = 100L
|
private const val ANIM_SNACKBAR_DELAY = 100L
|
||||||
private const val CFR_WIDTH_DIVIDER = 1.7
|
private const val CFR_WIDTH_DIVIDER = 1.7
|
||||||
private const val CFR_Y_OFFSET = -20
|
private const val CFR_Y_OFFSET = -20
|
||||||
private const val SELECTED_TAB_OFFSET = 20
|
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
private const val HEADER_MARGIN = 60
|
private const val HEADER_MARGIN = 60
|
||||||
|
|
||||||
private const val SNACKBAR_ELEVATION = 80f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper around sessions manager to observe changes in sessions.
|
|
||||||
* Similar to [mozilla.components.browser.session.utils.AllSessionsObserver] but ignores CustomTab sessions.
|
|
||||||
*
|
|
||||||
* Call [onStart] to start receiving updates into [onChanged] callback.
|
|
||||||
* Call [onStop] to stop receiving updates.
|
|
||||||
*
|
|
||||||
* @param manager [SessionManager] instance to subscribe to.
|
|
||||||
* @param observer [Session.Observer] instance that will recieve updates.
|
|
||||||
* @param onChanged callback that will be called when any of [SessionManager.Observer]'s events are fired.
|
|
||||||
*/
|
|
||||||
private class BrowserSessionsObserver(
|
|
||||||
private val manager: SessionManager,
|
|
||||||
private val store: BrowserStore,
|
|
||||||
private val observer: Session.Observer,
|
|
||||||
private val onChanged: () -> Unit
|
|
||||||
) : LifecycleObserver {
|
|
||||||
private var scope: CoroutineScope? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start observing
|
|
||||||
*/
|
|
||||||
@OnLifecycleEvent(Lifecycle.Event.ON_START)
|
|
||||||
fun onStart() {
|
|
||||||
manager.register(managerObserver)
|
|
||||||
subscribeToAll()
|
|
||||||
|
|
||||||
scope = store.flowScoped { flow ->
|
|
||||||
flow.ifChanged { it.media.aggregate }
|
|
||||||
.collect { onChanged() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop observing (will not receive updates till next [onStop] call)
|
|
||||||
*/
|
|
||||||
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
|
|
||||||
fun onStop() {
|
|
||||||
scope?.cancel()
|
|
||||||
manager.unregister(managerObserver)
|
|
||||||
unsubscribeFromAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeToAll() {
|
|
||||||
manager.sessions.forEach(::subscribeTo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun unsubscribeFromAll() {
|
|
||||||
manager.sessions.forEach(::unsubscribeFrom)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeTo(session: Session) {
|
|
||||||
session.register(observer)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun unsubscribeFrom(session: Session) {
|
|
||||||
session.unregister(observer)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val managerObserver = object : SessionManager.Observer {
|
|
||||||
override fun onSessionAdded(session: Session) {
|
|
||||||
subscribeTo(session)
|
|
||||||
onChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSessionsRestored() {
|
|
||||||
subscribeToAll()
|
|
||||||
onChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAllSessionsRemoved() {
|
|
||||||
unsubscribeFromAll()
|
|
||||||
onChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSessionRemoved(session: Session) {
|
|
||||||
unsubscribeFrom(session)
|
|
||||||
onChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSessionSelected(session: Session) {
|
|
||||||
onChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
package org.mozilla.fenix.home
|
package org.mozilla.fenix.home
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.session.SessionManager
|
|
||||||
import mozilla.components.browser.state.state.MediaState
|
import mozilla.components.browser.state.state.MediaState
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
|
@ -34,10 +32,6 @@ data class Tab(
|
||||||
val mediaState: MediaState.State
|
val mediaState: MediaState.State
|
||||||
)
|
)
|
||||||
|
|
||||||
fun List<Tab>.toSessionBundle(sessionManager: SessionManager): List<Session> {
|
|
||||||
return this.mapNotNull { sessionManager.findSessionById(it.sessionId) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state for the [HomeFragment].
|
* The state for the [HomeFragment].
|
||||||
*
|
*
|
||||||
|
@ -52,14 +46,12 @@ data class HomeFragmentState(
|
||||||
val collections: List<TabCollection>,
|
val collections: List<TabCollection>,
|
||||||
val expandedCollections: Set<Long>,
|
val expandedCollections: Set<Long>,
|
||||||
val mode: Mode,
|
val mode: Mode,
|
||||||
val tabs: List<Tab>,
|
|
||||||
val topSites: List<TopSite>,
|
val topSites: List<TopSite>,
|
||||||
val tip: Tip? = null
|
val tip: Tip? = null
|
||||||
) : State
|
) : State
|
||||||
|
|
||||||
sealed class HomeFragmentAction : Action {
|
sealed class HomeFragmentAction : Action {
|
||||||
data class Change(
|
data class Change(
|
||||||
val tabs: List<Tab>,
|
|
||||||
val topSites: List<TopSite>,
|
val topSites: List<TopSite>,
|
||||||
val mode: Mode,
|
val mode: Mode,
|
||||||
val collections: List<TabCollection>,
|
val collections: List<TabCollection>,
|
||||||
|
@ -71,8 +63,7 @@ sealed class HomeFragmentAction : Action {
|
||||||
HomeFragmentAction()
|
HomeFragmentAction()
|
||||||
|
|
||||||
data class CollectionsChange(val collections: List<TabCollection>) : HomeFragmentAction()
|
data class CollectionsChange(val collections: List<TabCollection>) : HomeFragmentAction()
|
||||||
data class ModeChange(val mode: Mode, val tabs: List<Tab> = emptyList()) : HomeFragmentAction()
|
data class ModeChange(val mode: Mode) : HomeFragmentAction()
|
||||||
data class TabsChange(val tabs: List<Tab>) : HomeFragmentAction()
|
|
||||||
data class TopSitesChange(val topSites: List<TopSite>) : HomeFragmentAction()
|
data class TopSitesChange(val topSites: List<TopSite>) : HomeFragmentAction()
|
||||||
data class RemoveTip(val tip: Tip) : HomeFragmentAction()
|
data class RemoveTip(val tip: Tip) : HomeFragmentAction()
|
||||||
}
|
}
|
||||||
|
@ -85,7 +76,6 @@ private fun homeFragmentStateReducer(
|
||||||
is HomeFragmentAction.Change -> state.copy(
|
is HomeFragmentAction.Change -> state.copy(
|
||||||
collections = action.collections,
|
collections = action.collections,
|
||||||
mode = action.mode,
|
mode = action.mode,
|
||||||
tabs = action.tabs,
|
|
||||||
topSites = action.topSites,
|
topSites = action.topSites,
|
||||||
tip = action.tip
|
tip = action.tip
|
||||||
)
|
)
|
||||||
|
@ -101,8 +91,7 @@ private fun homeFragmentStateReducer(
|
||||||
state.copy(expandedCollections = newExpandedCollection)
|
state.copy(expandedCollections = newExpandedCollection)
|
||||||
}
|
}
|
||||||
is HomeFragmentAction.CollectionsChange -> state.copy(collections = action.collections)
|
is HomeFragmentAction.CollectionsChange -> state.copy(collections = action.collections)
|
||||||
is HomeFragmentAction.ModeChange -> state.copy(mode = action.mode, tabs = action.tabs)
|
is HomeFragmentAction.ModeChange -> state.copy(mode = action.mode)
|
||||||
is HomeFragmentAction.TabsChange -> state.copy(tabs = action.tabs)
|
|
||||||
is HomeFragmentAction.TopSitesChange -> state.copy(topSites = action.topSites)
|
is HomeFragmentAction.TopSitesChange -> state.copy(topSites = action.topSites)
|
||||||
is HomeFragmentAction.RemoveTip -> { state.copy(tip = null) }
|
is HomeFragmentAction.RemoveTip -> { state.copy(tip = null) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@ import androidx.lifecycle.ViewModel
|
||||||
import mozilla.components.browser.state.state.content.DownloadState
|
import mozilla.components.browser.state.state.content.DownloadState
|
||||||
|
|
||||||
class SharedViewModel : ViewModel() {
|
class SharedViewModel : ViewModel() {
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to remember if we need to scroll to the selected tab in the homeFragment's recycleView see #7356
|
|
||||||
* */
|
|
||||||
var shouldScrollToSelectedTab: Boolean = false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores data needed for [DynamicDownloadDialog]. See #9044
|
* Stores data needed for [DynamicDownloadDialog]. See #9044
|
||||||
* Format: HashMap<sessionId, Pair<DownloadState, didFail>
|
* Format: HashMap<sessionId, Pair<DownloadState, didFail>
|
||||||
|
|
|
@ -7,29 +7,21 @@ package org.mozilla.fenix.home.sessioncontrol
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.android.synthetic.main.tab_list_row.*
|
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
import org.mozilla.fenix.components.tips.Tip
|
import org.mozilla.fenix.components.tips.Tip
|
||||||
import org.mozilla.fenix.ext.removeAndDisable
|
|
||||||
import org.mozilla.fenix.ext.removeTouchDelegate
|
|
||||||
import org.mozilla.fenix.home.OnboardingState
|
import org.mozilla.fenix.home.OnboardingState
|
||||||
import org.mozilla.fenix.home.Tab
|
import org.mozilla.fenix.home.Tab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageWithActionViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.SaveTabGroupViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSiteViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSiteViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
|
||||||
|
@ -48,55 +40,17 @@ import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||||
sealed class AdapterItem(@LayoutRes val viewType: Int) {
|
sealed class AdapterItem(@LayoutRes val viewType: Int) {
|
||||||
data class TipItem(val tip: Tip) : AdapterItem(
|
data class TipItem(val tip: Tip) : AdapterItem(
|
||||||
ButtonTipViewHolder.LAYOUT_ID)
|
ButtonTipViewHolder.LAYOUT_ID)
|
||||||
data class TabHeader(val isPrivate: Boolean, val hasTabs: Boolean) : AdapterItem(TabHeaderViewHolder.LAYOUT_ID)
|
|
||||||
data class TabItem(val tab: Tab) : AdapterItem(TabViewHolder.LAYOUT_ID) {
|
|
||||||
override fun sameAs(other: AdapterItem) = other is TabItem && tab.sessionId == other.tab.sessionId
|
|
||||||
|
|
||||||
// Tell the adapter exactly what values have changed so it only has to draw those
|
|
||||||
override fun getChangePayload(newItem: AdapterItem): Any? {
|
|
||||||
(newItem as TabItem).let {
|
|
||||||
val shouldUpdateFavicon =
|
|
||||||
newItem.tab.url != this.tab.url || newItem.tab.icon != this.tab.icon
|
|
||||||
val shouldUpdateHostname = newItem.tab.hostname != this.tab.hostname
|
|
||||||
val shouldUpdateTitle = newItem.tab.title != this.tab.title
|
|
||||||
val shouldUpdateSelected = newItem.tab.selected != this.tab.selected
|
|
||||||
val shouldUpdateMediaState = newItem.tab.mediaState != this.tab.mediaState
|
|
||||||
|
|
||||||
return AdapterItemDiffCallback.TabChangePayload(
|
|
||||||
tab = newItem.tab,
|
|
||||||
shouldUpdateFavicon = shouldUpdateFavicon,
|
|
||||||
shouldUpdateHostname = shouldUpdateHostname,
|
|
||||||
shouldUpdateTitle = shouldUpdateTitle,
|
|
||||||
shouldUpdateSelected = shouldUpdateSelected,
|
|
||||||
shouldUpdateMediaState = shouldUpdateMediaState
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class TopSiteList(val topSites: List<TopSite>) : AdapterItem(TopSiteViewHolder.LAYOUT_ID)
|
data class TopSiteList(val topSites: List<TopSite>) : AdapterItem(TopSiteViewHolder.LAYOUT_ID)
|
||||||
|
|
||||||
object SaveTabGroup : AdapterItem(SaveTabGroupViewHolder.LAYOUT_ID)
|
|
||||||
|
|
||||||
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
|
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
|
||||||
data class NoContentMessage(
|
data class NoContentMessage(
|
||||||
@StringRes val header: Int,
|
@StringRes val header: Int,
|
||||||
@StringRes val description: Int
|
@StringRes val description: Int
|
||||||
) : AdapterItem(NoContentMessageViewHolder.LAYOUT_ID)
|
) : AdapterItem(NoContentMessageViewHolder.LAYOUT_ID)
|
||||||
|
|
||||||
data class NoContentMessageWithAction(
|
|
||||||
@StringRes val header: Int,
|
|
||||||
@StringRes val description: Int,
|
|
||||||
@DrawableRes val buttonIcon: Int = 0,
|
|
||||||
@StringRes val buttonText: Int = 0,
|
|
||||||
val listener: (() -> Unit)? = null
|
|
||||||
) : AdapterItem(NoContentMessageWithActionViewHolder.LAYOUT_ID)
|
|
||||||
|
|
||||||
object CollectionHeader : AdapterItem(CollectionHeaderViewHolder.LAYOUT_ID)
|
object CollectionHeader : AdapterItem(CollectionHeaderViewHolder.LAYOUT_ID)
|
||||||
data class CollectionItem(
|
data class CollectionItem(
|
||||||
val collection: TabCollection,
|
val collection: TabCollection,
|
||||||
val expanded: Boolean,
|
val expanded: Boolean
|
||||||
val sessionHasOpenTabs: Boolean
|
|
||||||
) : AdapterItem(CollectionViewHolder.LAYOUT_ID) {
|
) : AdapterItem(CollectionViewHolder.LAYOUT_ID) {
|
||||||
override fun sameAs(other: AdapterItem) = other is CollectionItem && collection.id == other.collection.id
|
override fun sameAs(other: AdapterItem) = other is CollectionItem && collection.id == other.collection.id
|
||||||
}
|
}
|
||||||
|
@ -167,13 +121,9 @@ class SessionControlAdapter(
|
||||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
ButtonTipViewHolder.LAYOUT_ID -> ButtonTipViewHolder(view, interactor)
|
ButtonTipViewHolder.LAYOUT_ID -> ButtonTipViewHolder(view, interactor)
|
||||||
TabHeaderViewHolder.LAYOUT_ID -> TabHeaderViewHolder(view, interactor)
|
|
||||||
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, interactor)
|
|
||||||
TopSiteViewHolder.LAYOUT_ID -> TopSiteViewHolder(view, interactor)
|
TopSiteViewHolder.LAYOUT_ID -> TopSiteViewHolder(view, interactor)
|
||||||
SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, interactor)
|
|
||||||
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, interactor)
|
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, interactor)
|
||||||
NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view)
|
NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view)
|
||||||
NoContentMessageWithActionViewHolder.LAYOUT_ID -> NoContentMessageWithActionViewHolder(view)
|
|
||||||
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
|
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
|
||||||
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor)
|
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor)
|
||||||
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, interactor, differentLastItem = true)
|
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, interactor, differentLastItem = true)
|
||||||
|
@ -202,28 +152,16 @@ class SessionControlAdapter(
|
||||||
val tipItem = item as AdapterItem.TipItem
|
val tipItem = item as AdapterItem.TipItem
|
||||||
holder.bind(tipItem.tip)
|
holder.bind(tipItem.tip)
|
||||||
}
|
}
|
||||||
is TabHeaderViewHolder -> {
|
|
||||||
val tabHeader = item as AdapterItem.TabHeader
|
|
||||||
holder.bind(tabHeader.isPrivate, tabHeader.hasTabs)
|
|
||||||
}
|
|
||||||
is TabViewHolder -> {
|
|
||||||
holder.bindSession((item as AdapterItem.TabItem).tab)
|
|
||||||
}
|
|
||||||
is TopSiteViewHolder -> {
|
is TopSiteViewHolder -> {
|
||||||
holder.bind((item as AdapterItem.TopSiteList).topSites)
|
holder.bind((item as AdapterItem.TopSiteList).topSites)
|
||||||
}
|
}
|
||||||
is NoContentMessageWithActionViewHolder -> {
|
|
||||||
val listener = { interactor.onOpenNewTabClicked() }
|
|
||||||
val (header, description, buttonIcon, buttonText) = item as AdapterItem.NoContentMessageWithAction
|
|
||||||
holder.bind(header, description, buttonIcon, buttonText, listener)
|
|
||||||
}
|
|
||||||
is NoContentMessageViewHolder -> {
|
is NoContentMessageViewHolder -> {
|
||||||
val (header, description) = item as AdapterItem.NoContentMessage
|
val (header, description) = item as AdapterItem.NoContentMessage
|
||||||
holder.bind(header, description)
|
holder.bind(header, description)
|
||||||
}
|
}
|
||||||
is CollectionViewHolder -> {
|
is CollectionViewHolder -> {
|
||||||
val (collection, expanded, sessionHasOpenTabs) = item as AdapterItem.CollectionItem
|
val (collection, expanded) = item as AdapterItem.CollectionItem
|
||||||
holder.bindSession(collection, expanded, sessionHasOpenTabs)
|
holder.bindSession(collection, expanded)
|
||||||
}
|
}
|
||||||
is TabInCollectionViewHolder -> {
|
is TabInCollectionViewHolder -> {
|
||||||
val (collection, tab, isLastTab) = item as AdapterItem.TabInCollectionItem
|
val (collection, tab, isLastTab) = item as AdapterItem.TabInCollectionItem
|
||||||
|
@ -238,35 +176,4 @@ class SessionControlAdapter(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(
|
|
||||||
holder: RecyclerView.ViewHolder,
|
|
||||||
position: Int,
|
|
||||||
payloads: MutableList<Any>
|
|
||||||
) {
|
|
||||||
if (payloads.isEmpty()) {
|
|
||||||
onBindViewHolder(holder, position)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
(payloads[0] as AdapterItemDiffCallback.TabChangePayload).let {
|
|
||||||
(holder as TabViewHolder).updateTab(it.tab)
|
|
||||||
|
|
||||||
// Always set the visibility to GONE to avoid the play button sticking around from previous draws
|
|
||||||
holder.play_pause_button.removeTouchDelegate()
|
|
||||||
holder.play_pause_button.removeAndDisable()
|
|
||||||
|
|
||||||
if (it.shouldUpdateHostname) { holder.updateHostname(it.tab.hostname) }
|
|
||||||
if (it.shouldUpdateTitle) {
|
|
||||||
holder.updateTitle(it.tab.title)
|
|
||||||
holder.updateCloseButtonDescription(it.tab.title) }
|
|
||||||
if (it.shouldUpdateFavicon) {
|
|
||||||
holder.updateFavIcon(it.tab.url, it.tab.icon)
|
|
||||||
}
|
|
||||||
if (it.shouldUpdateSelected) { holder.updateSelected(it.tab.selected ?: false) }
|
|
||||||
if (it.shouldUpdateMediaState) {
|
|
||||||
holder.updatePlayPauseButton(it.tab.mediaState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,12 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.home.sessioncontrol
|
package org.mozilla.fenix.home.sessioncontrol
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
|
||||||
import mozilla.components.concept.engine.prompt.ShareData
|
import mozilla.components.concept.engine.prompt.ShareData
|
||||||
import mozilla.components.feature.media.ext.pauseIfPlaying
|
|
||||||
import mozilla.components.feature.media.ext.playIfPaused
|
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.tab.collections.ext.restore
|
import mozilla.components.feature.tab.collections.ext.restore
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
|
@ -21,7 +17,6 @@ import org.mozilla.fenix.BrowserDirection
|
||||||
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.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
|
||||||
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.TopSiteStorage
|
import org.mozilla.fenix.components.TopSiteStorage
|
||||||
|
@ -30,13 +25,11 @@ import org.mozilla.fenix.components.metrics.MetricController
|
||||||
import org.mozilla.fenix.components.tips.Tip
|
import org.mozilla.fenix.components.tips.Tip
|
||||||
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.sessionsOfType
|
|
||||||
import org.mozilla.fenix.home.HomeFragment
|
import org.mozilla.fenix.home.HomeFragment
|
||||||
import org.mozilla.fenix.home.HomeFragmentAction
|
import org.mozilla.fenix.home.HomeFragmentAction
|
||||||
import org.mozilla.fenix.home.HomeFragmentDirections
|
import org.mozilla.fenix.home.HomeFragmentDirections
|
||||||
import org.mozilla.fenix.home.HomeFragmentStore
|
import org.mozilla.fenix.home.HomeFragmentStore
|
||||||
import org.mozilla.fenix.home.Tab
|
import org.mozilla.fenix.home.Tab
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.settings.SupportUtils
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||||
|
|
||||||
|
@ -46,16 +39,6 @@ import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("TooManyFunctions")
|
@SuppressWarnings("TooManyFunctions")
|
||||||
interface SessionControlController {
|
interface SessionControlController {
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onCloseTab]
|
|
||||||
*/
|
|
||||||
fun handleCloseTab(sessionId: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onCloseAllTabs]
|
|
||||||
*/
|
|
||||||
fun handleCloseAllTabs(isPrivateMode: Boolean)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see [CollectionInteractor.onCollectionAddTabTapped]
|
* @see [CollectionInteractor.onCollectionAddTabTapped]
|
||||||
*/
|
*/
|
||||||
|
@ -91,16 +74,6 @@ interface SessionControlController {
|
||||||
*/
|
*/
|
||||||
fun handleOpenInPrivateTabClicked(topSite: TopSite)
|
fun handleOpenInPrivateTabClicked(topSite: TopSite)
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onPauseMediaClicked]
|
|
||||||
*/
|
|
||||||
fun handlePauseMediaClicked()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onPlayMediaClicked]
|
|
||||||
*/
|
|
||||||
fun handlePlayMediaClicked()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see [TabSessionInteractor.onPrivateBrowsingLearnMoreClicked]
|
* @see [TabSessionInteractor.onPrivateBrowsingLearnMoreClicked]
|
||||||
*/
|
*/
|
||||||
|
@ -116,26 +89,11 @@ interface SessionControlController {
|
||||||
*/
|
*/
|
||||||
fun handleRenameCollectionTapped(collection: TabCollection)
|
fun handleRenameCollectionTapped(collection: TabCollection)
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onSaveToCollection]
|
|
||||||
*/
|
|
||||||
fun handleSaveTabToCollection(selectedTabId: String?)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onSelectTab]
|
|
||||||
*/
|
|
||||||
fun handleSelectTab(tabView: View, sessionId: String)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see [TopSiteInteractor.onSelectTopSite]
|
* @see [TopSiteInteractor.onSelectTopSite]
|
||||||
*/
|
*/
|
||||||
fun handleSelectTopSite(url: String, isDefault: Boolean)
|
fun handleSelectTopSite(url: String, isDefault: Boolean)
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onShareTabs]
|
|
||||||
*/
|
|
||||||
fun handleShareTabs()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see [OnboardingInteractor.onStartBrowsingClicked]
|
* @see [OnboardingInteractor.onStartBrowsingClicked]
|
||||||
*/
|
*/
|
||||||
|
@ -161,32 +119,20 @@ interface SessionControlController {
|
||||||
*/
|
*/
|
||||||
fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean)
|
fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean)
|
||||||
|
|
||||||
/**
|
|
||||||
* @see [TabSessionInteractor.onOpenNewTabClicked]
|
|
||||||
*/
|
|
||||||
fun handleonOpenNewTabClicked()
|
|
||||||
|
|
||||||
fun handleCloseTip(tip: Tip)
|
fun handleCloseTip(tip: Tip)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
||||||
class DefaultSessionControlController(
|
class DefaultSessionControlController(
|
||||||
private val store: BrowserStore,
|
|
||||||
private val activity: HomeActivity,
|
private val activity: HomeActivity,
|
||||||
private val fragmentStore: HomeFragmentStore,
|
private val fragmentStore: HomeFragmentStore,
|
||||||
private val navController: NavController,
|
private val navController: NavController,
|
||||||
private val browsingModeManager: BrowsingModeManager,
|
|
||||||
private val viewLifecycleScope: CoroutineScope,
|
private val viewLifecycleScope: CoroutineScope,
|
||||||
private val closeTab: (sessionId: String) -> Unit,
|
|
||||||
private val closeAllTabs: (isPrivateMode: Boolean) -> Unit,
|
|
||||||
private val getListOfTabs: () -> List<Tab>,
|
private val getListOfTabs: () -> List<Tab>,
|
||||||
private val hideOnboarding: () -> Unit,
|
private val hideOnboarding: () -> Unit,
|
||||||
private val invokePendingDeleteJobs: () -> Unit,
|
|
||||||
private val registerCollectionStorageObserver: () -> Unit,
|
private val registerCollectionStorageObserver: () -> Unit,
|
||||||
private val scrollToTheTop: () -> Unit,
|
|
||||||
private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit,
|
private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit,
|
||||||
private val openSettingsScreen: () -> Unit,
|
private val openSettingsScreen: () -> Unit,
|
||||||
private val openSearchScreen: () -> Unit,
|
|
||||||
private val openWhatsNewLink: () -> Unit,
|
private val openWhatsNewLink: () -> Unit,
|
||||||
private val openPrivacyNotice: () -> Unit,
|
private val openPrivacyNotice: () -> Unit,
|
||||||
private val showTabTray: () -> Unit
|
private val showTabTray: () -> Unit
|
||||||
|
@ -200,14 +146,6 @@ class DefaultSessionControlController(
|
||||||
private val topSiteStorage: TopSiteStorage
|
private val topSiteStorage: TopSiteStorage
|
||||||
get() = activity.components.core.topSiteStorage
|
get() = activity.components.core.topSiteStorage
|
||||||
|
|
||||||
override fun handleCloseTab(sessionId: String) {
|
|
||||||
closeTab.invoke(sessionId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleCloseAllTabs(isPrivateMode: Boolean) {
|
|
||||||
closeAllTabs.invoke(isPrivateMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleCollectionAddTabTapped(collection: TabCollection) {
|
override fun handleCollectionAddTabTapped(collection: TabCollection) {
|
||||||
metrics.track(Event.CollectionAddTabPressed)
|
metrics.track(Event.CollectionAddTabPressed)
|
||||||
showCollectionCreationFragment(
|
showCollectionCreationFragment(
|
||||||
|
@ -217,8 +155,6 @@ class DefaultSessionControlController(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleCollectionOpenTabClicked(tab: ComponentTab) {
|
override fun handleCollectionOpenTabClicked(tab: ComponentTab) {
|
||||||
invokePendingDeleteJobs()
|
|
||||||
|
|
||||||
sessionManager.restore(
|
sessionManager.restore(
|
||||||
activity,
|
activity,
|
||||||
activity.components.core.engine,
|
activity.components.core.engine,
|
||||||
|
@ -239,8 +175,6 @@ class DefaultSessionControlController(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleCollectionOpenTabsTapped(collection: TabCollection) {
|
override fun handleCollectionOpenTabsTapped(collection: TabCollection) {
|
||||||
invokePendingDeleteJobs()
|
|
||||||
|
|
||||||
sessionManager.restore(
|
sessionManager.restore(
|
||||||
activity,
|
activity,
|
||||||
activity.components.core.engine,
|
activity.components.core.engine,
|
||||||
|
@ -250,12 +184,7 @@ class DefaultSessionControlController(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (activity.settings().useNewTabTray) {
|
showTabTray()
|
||||||
showTabTray()
|
|
||||||
} else {
|
|
||||||
scrollToTheTop()
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics.track(Event.CollectionAllTabsRestored)
|
metrics.track(Event.CollectionAllTabsRestored)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,14 +217,6 @@ class DefaultSessionControlController(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handlePauseMediaClicked() {
|
|
||||||
store.state.media.pauseIfPlaying()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handlePlayMediaClicked() {
|
|
||||||
store.state.media.playIfPaused()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handlePrivateBrowsingLearnMoreClicked() {
|
override fun handlePrivateBrowsingLearnMoreClicked() {
|
||||||
activity.openToBrowserAndLoad(
|
activity.openToBrowserAndLoad(
|
||||||
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic
|
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic
|
||||||
|
@ -324,35 +245,7 @@ class DefaultSessionControlController(
|
||||||
metrics.track(Event.CollectionRenamePressed)
|
metrics.track(Event.CollectionRenamePressed)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleSaveTabToCollection(selectedTabId: String?) {
|
|
||||||
if (browsingModeManager.mode.isPrivate) return
|
|
||||||
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
|
|
||||||
val tabs = getListOfTabs()
|
|
||||||
val step = when {
|
|
||||||
// Show the SelectTabs fragment if there are multiple opened tabs to select which tabs
|
|
||||||
// you want to save to a collection.
|
|
||||||
tabs.size > 1 -> SaveCollectionStep.SelectTabs
|
|
||||||
// If there is an existing tab collection, show the SelectCollection fragment to save
|
|
||||||
// the selected tab to a collection of your choice.
|
|
||||||
tabCollectionStorage.cachedTabCollections.isNotEmpty() -> SaveCollectionStep.SelectCollection
|
|
||||||
// Show the NameCollection fragment to create a new collection for the selected tab.
|
|
||||||
else -> SaveCollectionStep.NameCollection
|
|
||||||
}
|
|
||||||
|
|
||||||
showCollectionCreationFragment(step, selectedTabId?.let { arrayOf(it) })
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleSelectTab(tabView: View, sessionId: String) {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
val session = sessionManager.findSessionById(sessionId)
|
|
||||||
sessionManager.select(session!!)
|
|
||||||
activity.openToBrowser(BrowserDirection.FromHome)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleSelectTopSite(url: String, isDefault: Boolean) {
|
override fun handleSelectTopSite(url: String, isDefault: Boolean) {
|
||||||
invokePendingDeleteJobs()
|
|
||||||
metrics.track(Event.TopSiteOpenInNewTab)
|
metrics.track(Event.TopSiteOpenInNewTab)
|
||||||
if (isDefault) { metrics.track(Event.TopSiteOpenDefault) }
|
if (isDefault) { metrics.track(Event.TopSiteOpenDefault) }
|
||||||
if (url == SupportUtils.POCKET_TRENDING_URL) { metrics.track(Event.PocketTopSiteClicked) }
|
if (url == SupportUtils.POCKET_TRENDING_URL) { metrics.track(Event.PocketTopSiteClicked) }
|
||||||
|
@ -364,15 +257,6 @@ class DefaultSessionControlController(
|
||||||
activity.openToBrowser(BrowserDirection.FromHome)
|
activity.openToBrowser(BrowserDirection.FromHome)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleShareTabs() {
|
|
||||||
invokePendingDeleteJobs()
|
|
||||||
val shareData = sessionManager
|
|
||||||
.sessionsOfType(private = browsingModeManager.mode.isPrivate)
|
|
||||||
.map { ShareData(url = it.url, title = it.title) }
|
|
||||||
.toList()
|
|
||||||
showShareFragment(shareData)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleStartBrowsingClicked() {
|
override fun handleStartBrowsingClicked() {
|
||||||
hideOnboarding()
|
hideOnboarding()
|
||||||
}
|
}
|
||||||
|
@ -393,10 +277,6 @@ class DefaultSessionControlController(
|
||||||
fragmentStore.dispatch(HomeFragmentAction.CollectionExpanded(collection, expand))
|
fragmentStore.dispatch(HomeFragmentAction.CollectionExpanded(collection, expand))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleonOpenNewTabClicked() {
|
|
||||||
openSearchScreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleCloseTip(tip: Tip) {
|
override fun handleCloseTip(tip: Tip) {
|
||||||
fragmentStore.dispatch(HomeFragmentAction.RemoveTip(tip))
|
fragmentStore.dispatch(HomeFragmentAction.RemoveTip(tip))
|
||||||
}
|
}
|
||||||
|
@ -427,8 +307,4 @@ class DefaultSessionControlController(
|
||||||
)
|
)
|
||||||
navController.nav(R.id.homeFragment, directions)
|
navController.nav(R.id.homeFragment, directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,22 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.home.sessioncontrol
|
package org.mozilla.fenix.home.sessioncontrol
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import mozilla.components.feature.tab.collections.Tab
|
import mozilla.components.feature.tab.collections.Tab
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
import org.mozilla.fenix.components.tips.Tip
|
import org.mozilla.fenix.components.tips.Tip
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for tab related actions in the [SessionControlInteractor].
|
||||||
|
*/
|
||||||
|
interface TabSessionInteractor {
|
||||||
|
/**
|
||||||
|
* Shows the Private Browsing Learn More page in a new tab. Called when a user clicks on the
|
||||||
|
* "Common myths about private browsing" link in private mode.
|
||||||
|
*/
|
||||||
|
fun onPrivateBrowsingLearnMoreClicked()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for collection related actions in the [SessionControlInteractor].
|
* Interface for collection related actions in the [SessionControlInteractor].
|
||||||
*/
|
*/
|
||||||
|
@ -112,72 +122,6 @@ interface TipInteractor {
|
||||||
fun onCloseTip(tip: Tip)
|
fun onCloseTip(tip: Tip)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for tab related actions in the [SessionControlInteractor].
|
|
||||||
*/
|
|
||||||
interface TabSessionInteractor {
|
|
||||||
/**
|
|
||||||
* Closes the given tab. Called when a user swipes to close a tab or clicks on the Close Tab
|
|
||||||
* button in the tab view.
|
|
||||||
*
|
|
||||||
* @param sessionId The selected tab session id to close.
|
|
||||||
*/
|
|
||||||
fun onCloseTab(sessionId: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes all the tabs. Called when a user clicks on the Close Tabs button or "Close all tabs"
|
|
||||||
* tab header menu item.
|
|
||||||
*
|
|
||||||
* @param isPrivateMode True if the [BrowsingMode] is [Private] and false otherwise.
|
|
||||||
*/
|
|
||||||
fun onCloseAllTabs(isPrivateMode: Boolean)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses all playing [Media]. Called when a user clicks on the Pause button in the tab view.
|
|
||||||
*/
|
|
||||||
fun onPauseMediaClicked()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resumes playing all paused [Media]. Called when a user clicks on the Play button in the tab
|
|
||||||
* view.
|
|
||||||
*/
|
|
||||||
fun onPlayMediaClicked()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the Private Browsing Learn More page in a new tab. Called when a user clicks on the
|
|
||||||
* "Common myths about private browsing" link in private mode.
|
|
||||||
*/
|
|
||||||
fun onPrivateBrowsingLearnMoreClicked()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the given tab to collection. Called when a user clicks on the "Save to collection"
|
|
||||||
* button or tab header menu item, and on long click of an open tab.
|
|
||||||
*
|
|
||||||
* @param sessionId The selected tab session id to save.
|
|
||||||
*/
|
|
||||||
fun onSaveToCollection(sessionId: String?)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selects the given tab. Called when a user clicks on a tab.
|
|
||||||
*
|
|
||||||
* @param tabView [View] of the current Fragment to match with a View in the Fragment being
|
|
||||||
* navigated to.
|
|
||||||
* @param sessionId The tab session id to select.
|
|
||||||
*/
|
|
||||||
fun onSelectTab(tabView: View, sessionId: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shares the current opened tabs. Called when a user clicks on the Share Tabs button in private
|
|
||||||
* mode or tab header menu item.
|
|
||||||
*/
|
|
||||||
fun onShareTabs()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a new tab
|
|
||||||
*/
|
|
||||||
fun onOpenNewTabClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for top site related actions in the [SessionControlInteractor].
|
* Interface for top site related actions in the [SessionControlInteractor].
|
||||||
*/
|
*/
|
||||||
|
@ -214,15 +158,7 @@ interface TopSiteInteractor {
|
||||||
@SuppressWarnings("TooManyFunctions")
|
@SuppressWarnings("TooManyFunctions")
|
||||||
class SessionControlInteractor(
|
class SessionControlInteractor(
|
||||||
private val controller: SessionControlController
|
private val controller: SessionControlController
|
||||||
) : CollectionInteractor, OnboardingInteractor, TabSessionInteractor, TopSiteInteractor, TipInteractor {
|
) : CollectionInteractor, OnboardingInteractor, TopSiteInteractor, TipInteractor, TabSessionInteractor {
|
||||||
override fun onCloseTab(sessionId: String) {
|
|
||||||
controller.handleCloseTab(sessionId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCloseAllTabs(isPrivateMode: Boolean) {
|
|
||||||
controller.handleCloseAllTabs(isPrivateMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCollectionAddTabTapped(collection: TabCollection) {
|
override fun onCollectionAddTabTapped(collection: TabCollection) {
|
||||||
controller.handleCollectionAddTabTapped(collection)
|
controller.handleCollectionAddTabTapped(collection)
|
||||||
}
|
}
|
||||||
|
@ -251,18 +187,6 @@ class SessionControlInteractor(
|
||||||
controller.handleOpenInPrivateTabClicked(topSite)
|
controller.handleOpenInPrivateTabClicked(topSite)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPauseMediaClicked() {
|
|
||||||
controller.handlePauseMediaClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPlayMediaClicked() {
|
|
||||||
controller.handlePlayMediaClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrivateBrowsingLearnMoreClicked() {
|
|
||||||
controller.handlePrivateBrowsingLearnMoreClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRemoveTopSiteClicked(topSite: TopSite) {
|
override fun onRemoveTopSiteClicked(topSite: TopSite) {
|
||||||
controller.handleRemoveTopSiteClicked(topSite)
|
controller.handleRemoveTopSiteClicked(topSite)
|
||||||
}
|
}
|
||||||
|
@ -271,22 +195,10 @@ class SessionControlInteractor(
|
||||||
controller.handleRenameCollectionTapped(collection)
|
controller.handleRenameCollectionTapped(collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveToCollection(sessionId: String?) {
|
|
||||||
controller.handleSaveTabToCollection(sessionId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSelectTab(tabView: View, sessionId: String) {
|
|
||||||
controller.handleSelectTab(tabView, sessionId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSelectTopSite(url: String, isDefault: Boolean) {
|
override fun onSelectTopSite(url: String, isDefault: Boolean) {
|
||||||
controller.handleSelectTopSite(url, isDefault)
|
controller.handleSelectTopSite(url, isDefault)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onShareTabs() {
|
|
||||||
controller.handleShareTabs()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStartBrowsingClicked() {
|
override fun onStartBrowsingClicked() {
|
||||||
controller.handleStartBrowsingClicked()
|
controller.handleStartBrowsingClicked()
|
||||||
}
|
}
|
||||||
|
@ -307,11 +219,11 @@ class SessionControlInteractor(
|
||||||
controller.handleToggleCollectionExpanded(collection, expand)
|
controller.handleToggleCollectionExpanded(collection, expand)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenNewTabClicked() {
|
|
||||||
controller.handleonOpenNewTabClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCloseTip(tip: Tip) {
|
override fun onCloseTip(tip: Tip) {
|
||||||
controller.handleCloseTip(tip)
|
controller.handleCloseTip(tip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPrivateBrowsingLearnMoreClicked() {
|
||||||
|
controller.handlePrivateBrowsingLearnMoreClicked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.home.sessioncontrol
|
package org.mozilla.fenix.home.sessioncontrol
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
@ -19,16 +18,7 @@ import org.mozilla.fenix.home.HomeFragmentState
|
||||||
import org.mozilla.fenix.home.HomeScreenViewModel
|
import org.mozilla.fenix.home.HomeScreenViewModel
|
||||||
import org.mozilla.fenix.home.Mode
|
import org.mozilla.fenix.home.Mode
|
||||||
import org.mozilla.fenix.home.OnboardingState
|
import org.mozilla.fenix.home.OnboardingState
|
||||||
import org.mozilla.fenix.home.Tab
|
|
||||||
import org.mozilla.fenix.components.tips.Tip
|
import org.mozilla.fenix.components.tips.Tip
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
|
|
||||||
val noTabMessage = AdapterItem.NoContentMessageWithAction(
|
|
||||||
R.string.no_open_tabs_header_2,
|
|
||||||
R.string.no_open_tabs_description,
|
|
||||||
R.drawable.ic_new,
|
|
||||||
R.string.home_screen_shortcut_open_new_tab_2
|
|
||||||
)
|
|
||||||
|
|
||||||
val noCollectionMessage = AdapterItem.NoContentMessage(
|
val noCollectionMessage = AdapterItem.NoContentMessage(
|
||||||
R.string.no_collections_header,
|
R.string.no_collections_header,
|
||||||
|
@ -39,8 +29,6 @@ val noCollectionMessage = AdapterItem.NoContentMessage(
|
||||||
// When we remove the tabs from the home screen this will get much simpler again.
|
// When we remove the tabs from the home screen this will get much simpler again.
|
||||||
@SuppressWarnings("LongParameterList", "ComplexMethod")
|
@SuppressWarnings("LongParameterList", "ComplexMethod")
|
||||||
private fun normalModeAdapterItems(
|
private fun normalModeAdapterItems(
|
||||||
context: Context,
|
|
||||||
tabs: List<Tab>,
|
|
||||||
topSites: List<TopSite>,
|
topSites: List<TopSite>,
|
||||||
collections: List<TabCollection>,
|
collections: List<TabCollection>,
|
||||||
expandedCollections: Set<Long>,
|
expandedCollections: Set<Long>,
|
||||||
|
@ -54,60 +42,25 @@ private fun normalModeAdapterItems(
|
||||||
items.add(AdapterItem.TopSiteList(topSites))
|
items.add(AdapterItem.TopSiteList(topSites))
|
||||||
}
|
}
|
||||||
|
|
||||||
val useNewTabTray = context.settings().useNewTabTray
|
if (collections.isEmpty()) {
|
||||||
|
items.add(AdapterItem.CollectionHeader)
|
||||||
if (!useNewTabTray) {
|
items.add(noCollectionMessage)
|
||||||
items.add(AdapterItem.TabHeader(false, tabs.isNotEmpty()))
|
} else {
|
||||||
}
|
showCollections(collections, expandedCollections, items)
|
||||||
|
|
||||||
when {
|
|
||||||
tabs.isNotEmpty() && collections.isNotEmpty() -> {
|
|
||||||
if (!useNewTabTray) { showTabs(items, tabs) }
|
|
||||||
showCollections(collections, expandedCollections, tabs, items)
|
|
||||||
}
|
|
||||||
|
|
||||||
tabs.isNotEmpty() && collections.isEmpty() -> {
|
|
||||||
if (!useNewTabTray) { showTabs(items, tabs) }
|
|
||||||
items.add(AdapterItem.CollectionHeader)
|
|
||||||
items.add(noCollectionMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
tabs.isEmpty() && collections.isNotEmpty() -> {
|
|
||||||
if (!useNewTabTray) { items.add(noTabMessage) }
|
|
||||||
showCollections(collections, expandedCollections, tabs, items)
|
|
||||||
}
|
|
||||||
|
|
||||||
tabs.isEmpty() && collections.isEmpty() && !useNewTabTray -> {
|
|
||||||
items.add(noTabMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
collections.isEmpty() && useNewTabTray -> {
|
|
||||||
items.add(AdapterItem.CollectionHeader)
|
|
||||||
items.add(noCollectionMessage)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showTabs(
|
|
||||||
items: MutableList<AdapterItem>,
|
|
||||||
tabs: List<Tab>
|
|
||||||
) {
|
|
||||||
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
|
|
||||||
items.add(AdapterItem.SaveTabGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showCollections(
|
private fun showCollections(
|
||||||
collections: List<TabCollection>,
|
collections: List<TabCollection>,
|
||||||
expandedCollections: Set<Long>,
|
expandedCollections: Set<Long>,
|
||||||
tabs: List<Tab>,
|
|
||||||
items: MutableList<AdapterItem>
|
items: MutableList<AdapterItem>
|
||||||
) {
|
) {
|
||||||
// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
|
// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
|
||||||
items.add(AdapterItem.CollectionHeader)
|
items.add(AdapterItem.CollectionHeader)
|
||||||
collections.map {
|
collections.map {
|
||||||
AdapterItem.CollectionItem(it, expandedCollections.contains(it.id), tabs.isNotEmpty())
|
AdapterItem.CollectionItem(it, expandedCollections.contains(it.id))
|
||||||
}.forEach {
|
}.forEach {
|
||||||
items.add(it)
|
items.add(it)
|
||||||
if (it.expanded) {
|
if (it.expanded) {
|
||||||
|
@ -116,25 +69,7 @@ private fun showCollections(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun privateModeAdapterItems(context: Context, tabs: List<Tab>): List<AdapterItem> {
|
private fun privateModeAdapterItems() = listOf(AdapterItem.PrivateBrowsingDescription)
|
||||||
val items = mutableListOf<AdapterItem>()
|
|
||||||
|
|
||||||
val useNewTabTray = context.settings().useNewTabTray
|
|
||||||
|
|
||||||
if (useNewTabTray) {
|
|
||||||
items.add(AdapterItem.PrivateBrowsingDescription)
|
|
||||||
} else {
|
|
||||||
items.add(AdapterItem.TabHeader(true, tabs.isNotEmpty()))
|
|
||||||
|
|
||||||
if (tabs.isNotEmpty()) {
|
|
||||||
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
|
|
||||||
} else {
|
|
||||||
items.add(AdapterItem.PrivateBrowsingDescription)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onboardingAdapterItems(onboardingState: OnboardingState): List<AdapterItem> {
|
private fun onboardingAdapterItems(onboardingState: OnboardingState): List<AdapterItem> {
|
||||||
val items: MutableList<AdapterItem> = mutableListOf(AdapterItem.OnboardingHeader)
|
val items: MutableList<AdapterItem> = mutableListOf(AdapterItem.OnboardingHeader)
|
||||||
|
@ -171,9 +106,9 @@ private fun onboardingAdapterItems(onboardingState: OnboardingState): List<Adapt
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun HomeFragmentState.toAdapterList(context: Context): List<AdapterItem> = when (mode) {
|
private fun HomeFragmentState.toAdapterList(): List<AdapterItem> = when (mode) {
|
||||||
is Mode.Normal -> normalModeAdapterItems(context, tabs, topSites, collections, expandedCollections, tip)
|
is Mode.Normal -> normalModeAdapterItems(topSites, collections, expandedCollections, tip)
|
||||||
is Mode.Private -> privateModeAdapterItems(context, tabs)
|
is Mode.Private -> privateModeAdapterItems()
|
||||||
is Mode.Onboarding -> onboardingAdapterItems(mode.state)
|
is Mode.Onboarding -> onboardingAdapterItems(mode.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +147,7 @@ class SessionControlView(
|
||||||
sessionControlAdapter.submitList(null)
|
sessionControlAdapter.submitList(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val stateAdapterList = state.toAdapterList(view.context)
|
val stateAdapterList = state.toAdapterList()
|
||||||
|
|
||||||
if (homeScreenViewModel.shouldScrollToTopSites) {
|
if (homeScreenViewModel.shouldScrollToTopSites) {
|
||||||
sessionControlAdapter.submitList(stateAdapterList) {
|
sessionControlAdapter.submitList(stateAdapterList) {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
|
|
||||||
|
|
||||||
class SwipeToDeleteCallback(
|
class SwipeToDeleteCallback(
|
||||||
val interactor: SessionControlInteractor
|
val interactor: SessionControlInteractor
|
||||||
|
@ -29,7 +28,6 @@ class SwipeToDeleteCallback(
|
||||||
|
|
||||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||||
when (viewHolder) {
|
when (viewHolder) {
|
||||||
is TabViewHolder -> interactor.onCloseTab(viewHolder.tab?.sessionId!!)
|
|
||||||
is TabInCollectionViewHolder -> {
|
is TabInCollectionViewHolder -> {
|
||||||
interactor.onCollectionRemoveTab(viewHolder.collection, viewHolder.tab)
|
interactor.onCollectionRemoveTab(viewHolder.collection, viewHolder.tab)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +106,7 @@ class SwipeToDeleteCallback(
|
||||||
viewHolder: RecyclerView.ViewHolder
|
viewHolder: RecyclerView.ViewHolder
|
||||||
): Int {
|
): Int {
|
||||||
return if (recyclerView.hasWindowFocus() &&
|
return if (recyclerView.hasWindowFocus() &&
|
||||||
(viewHolder is TabViewHolder || viewHolder is TabInCollectionViewHolder)
|
viewHolder is TabInCollectionViewHolder
|
||||||
) {
|
) {
|
||||||
super.getSwipeDirs(recyclerView, viewHolder)
|
super.getSwipeDirs(recyclerView, viewHolder)
|
||||||
} else 0
|
} else 0
|
||||||
|
|
|
@ -11,9 +11,11 @@ import androidx.core.graphics.BlendModeCompat.SRC_IN
|
||||||
import kotlinx.android.synthetic.main.collection_home_list_row.*
|
import kotlinx.android.synthetic.main.collection_home_list_row.*
|
||||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||||
|
import mozilla.components.browser.state.selector.normalTabs
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.ViewHolder
|
import org.mozilla.fenix.ext.ViewHolder
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.getIconColor
|
import org.mozilla.fenix.ext.getIconColor
|
||||||
import org.mozilla.fenix.ext.increaseTapArea
|
import org.mozilla.fenix.ext.increaseTapArea
|
||||||
import org.mozilla.fenix.ext.removeAndDisable
|
import org.mozilla.fenix.ext.removeAndDisable
|
||||||
|
@ -29,11 +31,13 @@ class CollectionViewHolder(
|
||||||
|
|
||||||
private lateinit var collection: TabCollection
|
private lateinit var collection: TabCollection
|
||||||
private var expanded = false
|
private var expanded = false
|
||||||
private var sessionHasOpenTabs = false
|
|
||||||
private var collectionMenu: CollectionItemMenu
|
private var collectionMenu: CollectionItemMenu
|
||||||
|
|
||||||
init {
|
init {
|
||||||
collectionMenu = CollectionItemMenu(view.context, sessionHasOpenTabs) {
|
collectionMenu = CollectionItemMenu(
|
||||||
|
view.context,
|
||||||
|
{ view.context.components.core.store.state.normalTabs.isNotEmpty() }
|
||||||
|
) {
|
||||||
when (it) {
|
when (it) {
|
||||||
is CollectionItemMenu.Item.DeleteCollection -> interactor.onDeleteCollectionTapped(collection)
|
is CollectionItemMenu.Item.DeleteCollection -> interactor.onDeleteCollectionTapped(collection)
|
||||||
is CollectionItemMenu.Item.AddTab -> interactor.onCollectionAddTabTapped(collection)
|
is CollectionItemMenu.Item.AddTab -> interactor.onCollectionAddTabTapped(collection)
|
||||||
|
@ -58,11 +62,9 @@ class CollectionViewHolder(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bindSession(collection: TabCollection, expanded: Boolean, sessionHasOpenTabs: Boolean) {
|
fun bindSession(collection: TabCollection, expanded: Boolean) {
|
||||||
this.collection = collection
|
this.collection = collection
|
||||||
this.expanded = expanded
|
this.expanded = expanded
|
||||||
this.sessionHasOpenTabs = sessionHasOpenTabs
|
|
||||||
collectionMenu.sessionHasOpenTabs = sessionHasOpenTabs
|
|
||||||
updateCollectionUI()
|
updateCollectionUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +108,7 @@ class CollectionViewHolder(
|
||||||
|
|
||||||
class CollectionItemMenu(
|
class CollectionItemMenu(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
var sessionHasOpenTabs: Boolean,
|
private val shouldShowAddTab: () -> Boolean,
|
||||||
private val onItemTapped: (Item) -> Unit = {}
|
private val onItemTapped: (Item) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
sealed class Item {
|
sealed class Item {
|
||||||
|
@ -136,7 +138,7 @@ class CollectionItemMenu(
|
||||||
context.getString(R.string.add_tab)
|
context.getString(R.string.add_tab)
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(Item.AddTab)
|
onItemTapped.invoke(Item.AddTab)
|
||||||
}.apply { visible = { sessionHasOpenTabs } },
|
}.apply { visible = shouldShowAddTab },
|
||||||
|
|
||||||
SimpleBrowserMenuItem(
|
SimpleBrowserMenuItem(
|
||||||
context.getString(R.string.collection_delete),
|
context.getString(R.string.collection_delete),
|
||||||
|
|
|
@ -1,50 +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.home.sessioncontrol.viewholders
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import kotlinx.android.synthetic.main.no_content_message_with_action.*
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
|
|
||||||
class NoContentMessageWithActionViewHolder(view: View) : NoContentMessageViewHolder(view) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param header ID of string resource for title text.
|
|
||||||
* @param description ID of string resource for description text.
|
|
||||||
* @param buttonIcon Optional ID of drawable resource for button icon.
|
|
||||||
* @param buttonText Optional ID of string resource for button text.
|
|
||||||
* @param listener Optional Callback to be invoked when the button is clicked.
|
|
||||||
*/
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
fun bind(
|
|
||||||
@StringRes header: Int,
|
|
||||||
@StringRes description: Int,
|
|
||||||
@DrawableRes buttonIcon: Int = 0,
|
|
||||||
@StringRes buttonText: Int = 0,
|
|
||||||
listener: (() -> Unit)? = null
|
|
||||||
) {
|
|
||||||
super.bind(header, description)
|
|
||||||
with(itemView.context) {
|
|
||||||
|
|
||||||
if (buttonIcon != 0 || buttonText != 0) {
|
|
||||||
add_new_tab_button.apply {
|
|
||||||
isVisible = true
|
|
||||||
icon = getDrawable(buttonIcon)
|
|
||||||
text = getString(buttonText)
|
|
||||||
setOnClickListener {
|
|
||||||
listener?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val LAYOUT_ID = R.layout.no_content_message_with_action
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +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.home.sessioncontrol.viewholders
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import kotlinx.android.synthetic.main.save_to_collection_button.view.*
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabSessionInteractor
|
|
||||||
|
|
||||||
class SaveTabGroupViewHolder(
|
|
||||||
view: View,
|
|
||||||
private val interactor: TabSessionInteractor
|
|
||||||
) : RecyclerView.ViewHolder(view) {
|
|
||||||
|
|
||||||
init {
|
|
||||||
view.save_tab_group_button.setOnClickListener {
|
|
||||||
view.context.components.analytics.metrics
|
|
||||||
.track(Event.CollectionSaveButtonPressed(TELEMETRY_HOME_IDENTIFIER))
|
|
||||||
interactor.onSaveToCollection(sessionId = null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TELEMETRY_HOME_IDENTIFIER = "home"
|
|
||||||
const val LAYOUT_ID = R.layout.save_to_collection_button
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,119 +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.home.sessioncontrol.viewholders
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.PopupWindow
|
|
||||||
import androidx.core.view.isInvisible
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import kotlinx.android.synthetic.main.tab_header.*
|
|
||||||
import mozilla.components.browser.menu.BrowserMenu
|
|
||||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
|
||||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.ext.ViewHolder
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
|
||||||
|
|
||||||
class TabHeaderViewHolder(
|
|
||||||
view: View,
|
|
||||||
private val interactor: SessionControlInteractor
|
|
||||||
) : ViewHolder(view) {
|
|
||||||
private var isPrivate = false
|
|
||||||
private var tabsMenu: TabHeaderMenu
|
|
||||||
|
|
||||||
init {
|
|
||||||
tabsMenu = TabHeaderMenu(view.context, isPrivate) {
|
|
||||||
when (it) {
|
|
||||||
is TabHeaderMenu.Item.Share -> interactor.onShareTabs()
|
|
||||||
is TabHeaderMenu.Item.CloseAll -> interactor.onCloseAllTabs(isPrivate)
|
|
||||||
is TabHeaderMenu.Item.SaveToCollection -> {
|
|
||||||
interactor.onSaveToCollection(null)
|
|
||||||
view.context.components.analytics.metrics
|
|
||||||
.track(Event.CollectionSaveButtonPressed(TELEMETRY_HOME_MENU_IDENITIFIER))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
share_tabs_button.setOnClickListener {
|
|
||||||
interactor.onShareTabs()
|
|
||||||
}
|
|
||||||
|
|
||||||
close_tabs_button.setOnClickListener {
|
|
||||||
it.context.components.analytics.metrics.track(Event.PrivateBrowsingGarbageIconTapped)
|
|
||||||
interactor.onCloseAllTabs(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
tabs_overflow_button.run {
|
|
||||||
var menu: PopupWindow? = null
|
|
||||||
setOnClickListener {
|
|
||||||
if (menu == null) {
|
|
||||||
menu = tabsMenu.menuBuilder
|
|
||||||
.build(it.context)
|
|
||||||
.show(
|
|
||||||
anchor = it,
|
|
||||||
orientation = BrowserMenu.Orientation.DOWN,
|
|
||||||
onDismiss = { menu = null }
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
menu?.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bind(isPrivate: Boolean, hasTabs: Boolean) {
|
|
||||||
this.isPrivate = isPrivate
|
|
||||||
tabsMenu.isPrivate = isPrivate
|
|
||||||
|
|
||||||
val headerTextResourceId =
|
|
||||||
if (isPrivate) R.string.tabs_header_private_tabs_title else R.string.tab_header_label
|
|
||||||
header_text.text = itemView.context.getString(headerTextResourceId)
|
|
||||||
share_tabs_button.isInvisible = !isPrivate || !hasTabs
|
|
||||||
close_tabs_button.isInvisible = !isPrivate || !hasTabs
|
|
||||||
tabs_overflow_button.isVisible = !isPrivate && hasTabs
|
|
||||||
}
|
|
||||||
|
|
||||||
class TabHeaderMenu(
|
|
||||||
private val context: Context,
|
|
||||||
var isPrivate: Boolean,
|
|
||||||
private val onItemTapped: (Item) -> Unit = {}
|
|
||||||
) {
|
|
||||||
sealed class Item {
|
|
||||||
object CloseAll : Item()
|
|
||||||
object Share : Item()
|
|
||||||
object SaveToCollection : Item()
|
|
||||||
}
|
|
||||||
|
|
||||||
val menuBuilder by lazy { BrowserMenuBuilder(menuItems) }
|
|
||||||
|
|
||||||
private val menuItems by lazy {
|
|
||||||
listOf(
|
|
||||||
SimpleBrowserMenuItem(
|
|
||||||
context.getString(R.string.tabs_menu_close_all_tabs)
|
|
||||||
) {
|
|
||||||
onItemTapped.invoke(Item.CloseAll)
|
|
||||||
},
|
|
||||||
SimpleBrowserMenuItem(
|
|
||||||
context.getString(R.string.tabs_menu_share_tabs)
|
|
||||||
) {
|
|
||||||
onItemTapped.invoke(Item.Share)
|
|
||||||
},
|
|
||||||
SimpleBrowserMenuItem(
|
|
||||||
context.getString(R.string.tabs_menu_save_to_collection)
|
|
||||||
) {
|
|
||||||
onItemTapped.invoke(Item.SaveToCollection)
|
|
||||||
}.apply { visible = { !isPrivate } }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TELEMETRY_HOME_MENU_IDENITIFIER = "homeMenu"
|
|
||||||
const val LAYOUT_ID = R.layout.tab_header
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -42,7 +42,7 @@ class TabInCollectionViewHolder(
|
||||||
0,
|
0,
|
||||||
view.width,
|
view.width,
|
||||||
view.height,
|
view.height,
|
||||||
TabViewHolder.favIconBorderRadiusInPx.dpToFloat(view.context.resources.displayMetrics)
|
FAV_ICON_BORDER_RADIUS_IN_DP.dpToFloat(view.context.resources.displayMetrics)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,5 +82,6 @@ class TabInCollectionViewHolder(
|
||||||
companion object {
|
companion object {
|
||||||
const val buttonIncreaseDps = 12
|
const val buttonIncreaseDps = 12
|
||||||
const val LAYOUT_ID = R.layout.list_element
|
const val LAYOUT_ID = R.layout.list_element
|
||||||
|
const val FAV_ICON_BORDER_RADIUS_IN_DP = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,171 +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.home.sessioncontrol.viewholders
|
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Outline
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewOutlineProvider
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
|
||||||
import kotlinx.android.synthetic.main.tab_list_row.*
|
|
||||||
import mozilla.components.browser.state.state.MediaState
|
|
||||||
import mozilla.components.browser.toolbar.MAX_URI_LENGTH
|
|
||||||
import mozilla.components.support.ktx.android.util.dpToFloat
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
|
||||||
import org.mozilla.fenix.ext.ViewHolder
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.increaseTapArea
|
|
||||||
import org.mozilla.fenix.ext.loadIntoView
|
|
||||||
import org.mozilla.fenix.ext.removeAndDisable
|
|
||||||
import org.mozilla.fenix.ext.removeTouchDelegate
|
|
||||||
import org.mozilla.fenix.ext.showAndEnable
|
|
||||||
import org.mozilla.fenix.home.Tab
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabSessionInteractor
|
|
||||||
|
|
||||||
class TabViewHolder(
|
|
||||||
view: View,
|
|
||||||
interactor: TabSessionInteractor
|
|
||||||
) : ViewHolder(view) {
|
|
||||||
|
|
||||||
internal var tab: Tab? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
item_tab.setOnClickListener {
|
|
||||||
interactor.onSelectTab(it, tab?.sessionId!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
item_tab.setOnLongClickListener {
|
|
||||||
view.context.components.analytics.metrics.track(Event.CollectionTabLongPressed)
|
|
||||||
interactor.onSaveToCollection(tab?.sessionId!!)
|
|
||||||
return@setOnLongClickListener true
|
|
||||||
}
|
|
||||||
|
|
||||||
close_tab_button.setOnClickListener {
|
|
||||||
interactor.onCloseTab(tab?.sessionId!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
play_pause_button.setOnClickListener {
|
|
||||||
when (tab?.mediaState) {
|
|
||||||
MediaState.State.PLAYING -> {
|
|
||||||
it.context.components.analytics.metrics.track(Event.TabMediaPause)
|
|
||||||
interactor.onPauseMediaClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaState.State.PAUSED -> {
|
|
||||||
it.context.components.analytics.metrics.track(Event.TabMediaPlay)
|
|
||||||
interactor.onPlayMediaClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaState.State.NONE -> throw AssertionError(
|
|
||||||
"Play/Pause button clicked without play/pause state."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
favicon_image.clipToOutline = true
|
|
||||||
favicon_image.outlineProvider = object : ViewOutlineProvider() {
|
|
||||||
override fun getOutline(view: View?, outline: Outline?) {
|
|
||||||
outline?.setRoundRect(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
view!!.width,
|
|
||||||
view.height,
|
|
||||||
favIconBorderRadiusInPx.dpToFloat(view.context.resources.displayMetrics)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun bindSession(tab: Tab) {
|
|
||||||
updateTab(tab)
|
|
||||||
updateTitle(tab.title)
|
|
||||||
// Truncate to MAX_URI_LENGTH to prevent the UI from locking up for
|
|
||||||
// extremely large URLs such as data URIs or bookmarklets. The same
|
|
||||||
// is done in the toolbar and awesomebar:
|
|
||||||
// https://github.com/mozilla-mobile/fenix/issues/1824
|
|
||||||
// https://github.com/mozilla-mobile/android-components/issues/6985
|
|
||||||
updateHostname(tab.hostname.take(MAX_URI_LENGTH))
|
|
||||||
updateFavIcon(tab.url, tab.icon)
|
|
||||||
updateSelected(tab.selected ?: false)
|
|
||||||
updatePlayPauseButton(tab.mediaState)
|
|
||||||
item_tab.transitionName = "$TAB_ITEM_TRANSITION_NAME${tab.sessionId}"
|
|
||||||
updateCloseButtonDescription(tab.title)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updatePlayPauseButton(mediaState: MediaState.State) {
|
|
||||||
with(play_pause_button) {
|
|
||||||
invalidate()
|
|
||||||
when (mediaState) {
|
|
||||||
MediaState.State.PAUSED -> {
|
|
||||||
showAndEnable()
|
|
||||||
play_pause_button.increaseTapArea(PLAY_PAUSE_BUTTON_EXTRA_DPS)
|
|
||||||
contentDescription =
|
|
||||||
context.getString(R.string.mozac_feature_media_notification_action_play)
|
|
||||||
setImageDrawable(
|
|
||||||
AppCompatResources.getDrawable(
|
|
||||||
context,
|
|
||||||
R.drawable.play_with_background
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaState.State.PLAYING -> {
|
|
||||||
showAndEnable()
|
|
||||||
play_pause_button.increaseTapArea(PLAY_PAUSE_BUTTON_EXTRA_DPS)
|
|
||||||
contentDescription =
|
|
||||||
context.getString(R.string.mozac_feature_media_notification_action_pause)
|
|
||||||
setImageDrawable(
|
|
||||||
AppCompatResources.getDrawable(
|
|
||||||
context,
|
|
||||||
R.drawable.pause_with_background
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaState.State.NONE -> {
|
|
||||||
removeTouchDelegate()
|
|
||||||
removeAndDisable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateTab(tab: Tab) {
|
|
||||||
this.tab = tab
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateTitle(text: String) {
|
|
||||||
tab_title.text = text
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateHostname(text: String) {
|
|
||||||
hostname.text = text
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateFavIcon(url: String, icon: Bitmap?) {
|
|
||||||
if (icon == null) {
|
|
||||||
favicon_image.context.components.core.icons.loadIntoView(favicon_image, url)
|
|
||||||
} else {
|
|
||||||
favicon_image.setImageBitmap(icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateSelected(selected: Boolean) {
|
|
||||||
selected_border.visibility = if (selected) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun updateCloseButtonDescription(title: String) {
|
|
||||||
close_tab_button.contentDescription =
|
|
||||||
close_tab_button.context.getString(R.string.close_tab_title, title)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAB_ITEM_TRANSITION_NAME = "tab_item"
|
|
||||||
private const val PLAY_PAUSE_BUTTON_EXTRA_DPS = 24
|
|
||||||
const val LAYOUT_ID = R.layout.tab_list_row
|
|
||||||
const val favIconBorderRadiusInPx = 4
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,10 +6,7 @@ package org.mozilla.fenix.settings
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreference
|
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.getPreferenceKey
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,13 +20,5 @@ class SecretSettingsPreference : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.secret_settings_preferences, rootKey)
|
setPreferencesFromResource(R.xml.secret_settings_preferences, rootKey)
|
||||||
updatePreferences()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updatePreferences() {
|
|
||||||
findPreference<SwitchPreference>(getPreferenceKey(R.string.pref_key_enable_new_tab_tray))?.apply {
|
|
||||||
onPreferenceChangeListener = SharedPreferenceUpdater()
|
|
||||||
isChecked = context.settings().useNewTabTray
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import mozilla.components.support.ktx.android.content.longPreference
|
||||||
import mozilla.components.support.ktx.android.content.stringPreference
|
import mozilla.components.support.ktx.android.content.stringPreference
|
||||||
import org.mozilla.fenix.BuildConfig
|
import org.mozilla.fenix.BuildConfig
|
||||||
import org.mozilla.fenix.Config
|
import org.mozilla.fenix.Config
|
||||||
import org.mozilla.fenix.FeatureFlags
|
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.components.metrics.MozillaProductDetector
|
import org.mozilla.fenix.components.metrics.MozillaProductDetector
|
||||||
|
@ -756,17 +755,6 @@ class Settings private constructor(
|
||||||
default = 0
|
default = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
var useNewTabTray: Boolean
|
|
||||||
get() = preferences.let {
|
|
||||||
val prefKey = appContext.getPreferenceKey(R.string.pref_key_enable_new_tab_tray)
|
|
||||||
val useNewTabTray = it.getBoolean(prefKey, false)
|
|
||||||
FeatureFlags.tabTray && useNewTabTray }
|
|
||||||
set(value) {
|
|
||||||
preferences.edit()
|
|
||||||
.putBoolean(appContext.getPreferenceKey(R.string.pref_key_enable_new_tab_tray), value)
|
|
||||||
.apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var savedLoginsSortingStrategyString by stringPreference(
|
private var savedLoginsSortingStrategyString by stringPreference(
|
||||||
appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy),
|
appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy),
|
||||||
default = SavedLoginsFragment.SORTING_STRATEGY_ALPHABETICALLY
|
default = SavedLoginsFragment.SORTING_STRATEGY_ALPHABETICALLY
|
||||||
|
|
|
@ -140,26 +140,12 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:barrierDirection="start"
|
app:barrierDirection="start"
|
||||||
app:constraint_referenced_ids="tab_button,add_tab_button" />
|
app:constraint_referenced_ids="tab_button" />
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/add_tab_button"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/add_tab"
|
|
||||||
app:srcCompat="@drawable/ic_new"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/bottom_bar"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/bottom_bar"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/menuButton"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/toolbar_wrapper"/>
|
|
||||||
|
|
||||||
|
|
||||||
<org.mozilla.fenix.components.toolbar.TabCounter
|
<org.mozilla.fenix.components.toolbar.TabCounter
|
||||||
android:id="@+id/tab_button"
|
android:id="@+id/tab_button"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/bottom_bar"
|
app:layout_constraintTop_toTopOf="@id/bottom_bar"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/bottom_bar"
|
app:layout_constraintBottom_toBottomOf="@id/bottom_bar"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/menuButton"
|
app:layout_constraintEnd_toStartOf="@+id/menuButton"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/tab_item"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="88dp">
|
android:layout_height="88dp">
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,4 @@
|
||||||
- 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/. -->
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto"/>
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/pref_key_enable_new_tab_tray"
|
|
||||||
android:title="@string/preferences_debug_settings_enable_tab_tray"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.home
|
package org.mozilla.fenix.home
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
@ -17,7 +16,6 @@ import kotlinx.coroutines.newSingleThreadContext
|
||||||
import kotlinx.coroutines.test.resetMain
|
import kotlinx.coroutines.test.resetMain
|
||||||
import kotlinx.coroutines.test.setMain
|
import kotlinx.coroutines.test.setMain
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
|
||||||
import mozilla.components.concept.engine.Engine
|
import mozilla.components.concept.engine.Engine
|
||||||
import mozilla.components.feature.tab.collections.TabCollection
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.tabs.TabsUseCases
|
import mozilla.components.feature.tabs.TabsUseCases
|
||||||
|
@ -26,7 +24,6 @@ import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.BrowserDirection
|
import org.mozilla.fenix.BrowserDirection
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
|
||||||
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.metrics.MetricController
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
|
@ -39,22 +36,15 @@ import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||||
class DefaultSessionControlControllerTest {
|
class DefaultSessionControlControllerTest {
|
||||||
|
|
||||||
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
|
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
|
||||||
private val store: BrowserStore = mockk(relaxed = true)
|
|
||||||
private val activity: HomeActivity = mockk(relaxed = true)
|
private val activity: HomeActivity = mockk(relaxed = true)
|
||||||
private val fragmentStore: HomeFragmentStore = mockk(relaxed = true)
|
private val fragmentStore: HomeFragmentStore = mockk(relaxed = true)
|
||||||
private val navController: NavController = mockk(relaxed = true)
|
private val navController: NavController = mockk(relaxed = true)
|
||||||
private val browsingModeManager: BrowsingModeManager = mockk(relaxed = true)
|
|
||||||
private val closeTab: (sessionId: String) -> Unit = mockk(relaxed = true)
|
|
||||||
private val closeAllTabs: (isPrivateMode: Boolean) -> Unit = mockk(relaxed = true)
|
|
||||||
private val getListOfTabs: () -> List<Tab> = { emptyList() }
|
private val getListOfTabs: () -> List<Tab> = { emptyList() }
|
||||||
private val hideOnboarding: () -> Unit = mockk(relaxed = true)
|
private val hideOnboarding: () -> Unit = mockk(relaxed = true)
|
||||||
private val openSettingsScreen: () -> Unit = mockk(relaxed = true)
|
private val openSettingsScreen: () -> Unit = mockk(relaxed = true)
|
||||||
private val openSearchScreen: () -> Unit = mockk(relaxed = true)
|
|
||||||
private val openWhatsNewLink: () -> Unit = mockk(relaxed = true)
|
private val openWhatsNewLink: () -> Unit = mockk(relaxed = true)
|
||||||
private val openPrivacyNotice: () -> Unit = mockk(relaxed = true)
|
private val openPrivacyNotice: () -> Unit = mockk(relaxed = true)
|
||||||
private val invokePendingDeleteJobs: () -> Unit = mockk(relaxed = true)
|
|
||||||
private val registerCollectionStorageObserver: () -> Unit = mockk(relaxed = true)
|
private val registerCollectionStorageObserver: () -> Unit = mockk(relaxed = true)
|
||||||
private val scrollToTheTop: () -> Unit = mockk(relaxed = true)
|
|
||||||
private val showTabTray: () -> Unit = mockk(relaxed = true)
|
private val showTabTray: () -> Unit = mockk(relaxed = true)
|
||||||
private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit =
|
private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit =
|
||||||
mockk(relaxed = true)
|
mockk(relaxed = true)
|
||||||
|
@ -80,26 +70,18 @@ class DefaultSessionControlControllerTest {
|
||||||
every { state.collections } returns emptyList()
|
every { state.collections } returns emptyList()
|
||||||
every { state.expandedCollections } returns emptySet()
|
every { state.expandedCollections } returns emptySet()
|
||||||
every { state.mode } returns Mode.Normal
|
every { state.mode } returns Mode.Normal
|
||||||
every { state.tabs } returns emptyList()
|
|
||||||
every { activity.components.analytics.metrics } returns metrics
|
every { activity.components.analytics.metrics } returns metrics
|
||||||
|
|
||||||
controller = DefaultSessionControlController(
|
controller = DefaultSessionControlController(
|
||||||
store = store,
|
|
||||||
activity = activity,
|
activity = activity,
|
||||||
fragmentStore = fragmentStore,
|
fragmentStore = fragmentStore,
|
||||||
navController = navController,
|
navController = navController,
|
||||||
browsingModeManager = browsingModeManager,
|
|
||||||
viewLifecycleScope = MainScope(),
|
viewLifecycleScope = MainScope(),
|
||||||
closeTab = closeTab,
|
|
||||||
closeAllTabs = closeAllTabs,
|
|
||||||
getListOfTabs = getListOfTabs,
|
getListOfTabs = getListOfTabs,
|
||||||
hideOnboarding = hideOnboarding,
|
hideOnboarding = hideOnboarding,
|
||||||
invokePendingDeleteJobs = invokePendingDeleteJobs,
|
|
||||||
registerCollectionStorageObserver = registerCollectionStorageObserver,
|
registerCollectionStorageObserver = registerCollectionStorageObserver,
|
||||||
scrollToTheTop = scrollToTheTop,
|
|
||||||
showDeleteCollectionPrompt = showDeleteCollectionPrompt,
|
showDeleteCollectionPrompt = showDeleteCollectionPrompt,
|
||||||
openSettingsScreen = openSettingsScreen,
|
openSettingsScreen = openSettingsScreen,
|
||||||
openSearchScreen = openSearchScreen,
|
|
||||||
openWhatsNewLink = openWhatsNewLink,
|
openWhatsNewLink = openWhatsNewLink,
|
||||||
openPrivacyNotice = openPrivacyNotice,
|
openPrivacyNotice = openPrivacyNotice,
|
||||||
showTabTray = showTabTray
|
showTabTray = showTabTray
|
||||||
|
@ -112,20 +94,6 @@ class DefaultSessionControlControllerTest {
|
||||||
mainThreadSurrogate.close()
|
mainThreadSurrogate.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleCloseTab() {
|
|
||||||
val sessionId = "hello"
|
|
||||||
controller.handleCloseTab(sessionId)
|
|
||||||
verify { closeTab(sessionId) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleCloseAllTabs() {
|
|
||||||
val isPrivateMode = true
|
|
||||||
controller.handleCloseAllTabs(isPrivateMode)
|
|
||||||
verify { closeAllTabs(isPrivateMode) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun handleCollectionAddTabTapped() {
|
fun handleCollectionAddTabTapped() {
|
||||||
val collection: TabCollection = mockk(relaxed = true)
|
val collection: TabCollection = mockk(relaxed = true)
|
||||||
|
@ -137,7 +105,6 @@ class DefaultSessionControlControllerTest {
|
||||||
fun handleCollectionOpenTabClicked() {
|
fun handleCollectionOpenTabClicked() {
|
||||||
val tab: ComponentTab = mockk(relaxed = true)
|
val tab: ComponentTab = mockk(relaxed = true)
|
||||||
controller.handleCollectionOpenTabClicked(tab)
|
controller.handleCollectionOpenTabClicked(tab)
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
verify { metrics.track(Event.CollectionTabRestored) }
|
verify { metrics.track(Event.CollectionTabRestored) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,8 +112,6 @@ class DefaultSessionControlControllerTest {
|
||||||
fun handleCollectionOpenTabsTapped() {
|
fun handleCollectionOpenTabsTapped() {
|
||||||
val collection: TabCollection = mockk(relaxed = true)
|
val collection: TabCollection = mockk(relaxed = true)
|
||||||
controller.handleCollectionOpenTabsTapped(collection)
|
controller.handleCollectionOpenTabsTapped(collection)
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
verify { scrollToTheTop() }
|
|
||||||
verify { metrics.track(Event.CollectionAllTabsRestored) }
|
verify { metrics.track(Event.CollectionAllTabsRestored) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,27 +157,11 @@ class DefaultSessionControlControllerTest {
|
||||||
verify { metrics.track(Event.CollectionRenamePressed) }
|
verify { metrics.track(Event.CollectionRenamePressed) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleSaveTabToCollection() {
|
|
||||||
controller.handleSaveTabToCollection(selectedTabId = null)
|
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleSelectTab() {
|
|
||||||
val tabView: View = mockk(relaxed = true)
|
|
||||||
val sessionId = "hello"
|
|
||||||
controller.handleSelectTab(tabView, sessionId)
|
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
verify { activity.openToBrowser(BrowserDirection.FromHome) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun handleSelectDefaultTopSite() {
|
fun handleSelectDefaultTopSite() {
|
||||||
val topSiteUrl = "mozilla.org"
|
val topSiteUrl = "mozilla.org"
|
||||||
|
|
||||||
controller.handleSelectTopSite(topSiteUrl, true)
|
controller.handleSelectTopSite(topSiteUrl, true)
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
verify { metrics.track(Event.TopSiteOpenInNewTab) }
|
verify { metrics.track(Event.TopSiteOpenInNewTab) }
|
||||||
verify { metrics.track(Event.TopSiteOpenDefault) }
|
verify { metrics.track(Event.TopSiteOpenDefault) }
|
||||||
verify { tabsUseCases.addTab.invoke(
|
verify { tabsUseCases.addTab.invoke(
|
||||||
|
@ -228,7 +177,6 @@ class DefaultSessionControlControllerTest {
|
||||||
val topSiteUrl = "mozilla.org"
|
val topSiteUrl = "mozilla.org"
|
||||||
|
|
||||||
controller.handleSelectTopSite(topSiteUrl, false)
|
controller.handleSelectTopSite(topSiteUrl, false)
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
verify { metrics.track(Event.TopSiteOpenInNewTab) }
|
verify { metrics.track(Event.TopSiteOpenInNewTab) }
|
||||||
verify { tabsUseCases.addTab.invoke(
|
verify { tabsUseCases.addTab.invoke(
|
||||||
topSiteUrl,
|
topSiteUrl,
|
||||||
|
@ -238,12 +186,6 @@ class DefaultSessionControlControllerTest {
|
||||||
verify { activity.openToBrowser(BrowserDirection.FromHome) }
|
verify { activity.openToBrowser(BrowserDirection.FromHome) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun handleShareTabs() {
|
|
||||||
controller.handleShareTabs()
|
|
||||||
verify { invokePendingDeleteJobs() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun handleStartBrowsingClicked() {
|
fun handleStartBrowsingClicked() {
|
||||||
controller.handleStartBrowsingClicked()
|
controller.handleStartBrowsingClicked()
|
||||||
|
|
|
@ -53,7 +53,6 @@ class HomeFragmentStoreTest {
|
||||||
collections = emptyList(),
|
collections = emptyList(),
|
||||||
expandedCollections = emptySet(),
|
expandedCollections = emptySet(),
|
||||||
mode = currentMode.getCurrentMode(),
|
mode = currentMode.getCurrentMode(),
|
||||||
tabs = emptyList(),
|
|
||||||
topSites = emptyList()
|
topSites = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,38 +63,14 @@ class HomeFragmentStoreTest {
|
||||||
fun `Test toggling the mode in HomeFragmentStore`() = runBlocking {
|
fun `Test toggling the mode in HomeFragmentStore`() = runBlocking {
|
||||||
// Verify that the default mode and tab states of the HomeFragment are correct.
|
// Verify that the default mode and tab states of the HomeFragment are correct.
|
||||||
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
|
|
||||||
// Change the HomeFragmentStore to Private mode.
|
// Change the HomeFragmentStore to Private mode.
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(Mode.Private)).join()
|
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(Mode.Private)).join()
|
||||||
|
|
||||||
assertEquals(Mode.Private, homeFragmentStore.state.mode)
|
assertEquals(Mode.Private, homeFragmentStore.state.mode)
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
|
|
||||||
// Change the HomeFragmentStore back to Normal mode.
|
// Change the HomeFragmentStore back to Normal mode.
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(Mode.Normal)).join()
|
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(Mode.Normal)).join()
|
||||||
|
|
||||||
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Test toggling the mode with tabs in HomeFragmentStore`() = runBlocking {
|
|
||||||
// Verify that the default mode and tab states of the HomeFragment are correct.
|
|
||||||
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
|
|
||||||
// Add 2 Tabs to the HomeFragmentStore.
|
|
||||||
val tabs: List<Tab> = listOf(mockk(), mockk())
|
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(tabs)).join()
|
|
||||||
|
|
||||||
assertEquals(2, homeFragmentStore.state.tabs.size)
|
|
||||||
|
|
||||||
// Change the HomeFragmentStore to Private mode.
|
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(Mode.Private)).join()
|
|
||||||
|
|
||||||
assertEquals(Mode.Private, homeFragmentStore.state.mode)
|
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -120,18 +95,6 @@ class HomeFragmentStoreTest {
|
||||||
assertEquals(topSites, homeFragmentStore.state.topSites)
|
assertEquals(topSites, homeFragmentStore.state.topSites)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Test changing the tab in HomeFragmentStore`() = runBlocking {
|
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
|
|
||||||
val tab: Tab = mockk()
|
|
||||||
|
|
||||||
homeFragmentStore.dispatch(HomeFragmentAction.TabsChange(listOf(tab))).join()
|
|
||||||
|
|
||||||
assertTrue(homeFragmentStore.state.tabs.contains(tab))
|
|
||||||
assertEquals(1, homeFragmentStore.state.tabs.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Test changing the expanded collections in HomeFragmentStore`() = runBlocking {
|
fun `Test changing the expanded collections in HomeFragmentStore`() = runBlocking {
|
||||||
val collection: TabCollection = mockk<TabCollection>().apply {
|
val collection: TabCollection = mockk<TabCollection>().apply {
|
||||||
|
@ -147,29 +110,25 @@ class HomeFragmentStoreTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Test changing the collections, mode, tabs and top sites in the HomeFragmentStore`() = runBlocking {
|
fun `Test changing the collections, mode and top sites in the HomeFragmentStore`() = runBlocking {
|
||||||
// Verify that the default state of the HomeFragment is correct.
|
// Verify that the default state of the HomeFragment is correct.
|
||||||
assertEquals(0, homeFragmentStore.state.collections.size)
|
assertEquals(0, homeFragmentStore.state.collections.size)
|
||||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
|
||||||
assertEquals(0, homeFragmentStore.state.topSites.size)
|
assertEquals(0, homeFragmentStore.state.topSites.size)
|
||||||
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
||||||
|
|
||||||
val collections: List<TabCollection> = listOf(mockk())
|
val collections: List<TabCollection> = listOf(mockk())
|
||||||
val tabs: List<Tab> = listOf(mockk(), mockk())
|
|
||||||
val topSites: List<TopSite> = listOf(mockk(), mockk())
|
val topSites: List<TopSite> = listOf(mockk(), mockk())
|
||||||
|
|
||||||
homeFragmentStore.dispatch(
|
homeFragmentStore.dispatch(
|
||||||
HomeFragmentAction.Change(
|
HomeFragmentAction.Change(
|
||||||
collections = collections,
|
collections = collections,
|
||||||
mode = Mode.Private,
|
mode = Mode.Private,
|
||||||
tabs = tabs,
|
|
||||||
topSites = topSites
|
topSites = topSites
|
||||||
)
|
)
|
||||||
).join()
|
).join()
|
||||||
|
|
||||||
assertEquals(1, homeFragmentStore.state.collections.size)
|
assertEquals(1, homeFragmentStore.state.collections.size)
|
||||||
assertEquals(Mode.Private, homeFragmentStore.state.mode)
|
assertEquals(Mode.Private, homeFragmentStore.state.mode)
|
||||||
assertEquals(2, homeFragmentStore.state.tabs.size)
|
|
||||||
assertEquals(2, homeFragmentStore.state.topSites.size)
|
assertEquals(2, homeFragmentStore.state.topSites.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.home
|
package org.mozilla.fenix.home
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import mozilla.components.feature.tab.collections.Tab
|
import mozilla.components.feature.tab.collections.Tab
|
||||||
|
@ -25,20 +24,6 @@ class SessionControlInteractorTest {
|
||||||
interactor = SessionControlInteractor(controller)
|
interactor = SessionControlInteractor(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onCloseTab() {
|
|
||||||
val sessionId = "hello"
|
|
||||||
interactor.onCloseTab(sessionId)
|
|
||||||
verify { controller.handleCloseTab(sessionId) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onCloseAllTabs() {
|
|
||||||
val isPrivateMode = true
|
|
||||||
interactor.onCloseAllTabs(isPrivateMode)
|
|
||||||
verify { controller.handleCloseAllTabs(isPrivateMode) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onCollectionAddTabTapped() {
|
fun onCollectionAddTabTapped() {
|
||||||
val collection: TabCollection = mockk(relaxed = true)
|
val collection: TabCollection = mockk(relaxed = true)
|
||||||
|
@ -82,18 +67,6 @@ class SessionControlInteractorTest {
|
||||||
verify { controller.handleDeleteCollectionTapped(collection) }
|
verify { controller.handleDeleteCollectionTapped(collection) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onPauseMediaClicked() {
|
|
||||||
interactor.onPauseMediaClicked()
|
|
||||||
verify { controller.handlePauseMediaClicked() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onPlayMediaClicked() {
|
|
||||||
interactor.onPlayMediaClicked()
|
|
||||||
verify { controller.handlePlayMediaClicked() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onPrivateBrowsingLearnMoreClicked() {
|
fun onPrivateBrowsingLearnMoreClicked() {
|
||||||
interactor.onPrivateBrowsingLearnMoreClicked()
|
interactor.onPrivateBrowsingLearnMoreClicked()
|
||||||
|
@ -107,26 +80,6 @@ class SessionControlInteractorTest {
|
||||||
verify { controller.handleRenameCollectionTapped(collection) }
|
verify { controller.handleRenameCollectionTapped(collection) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onSaveToCollection() {
|
|
||||||
interactor.onSaveToCollection(null)
|
|
||||||
verify { controller.handleSaveTabToCollection(null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onSelectTab() {
|
|
||||||
val tabView: View = mockk(relaxed = true)
|
|
||||||
val sessionId = "hello"
|
|
||||||
interactor.onSelectTab(tabView, sessionId)
|
|
||||||
verify { controller.handleSelectTab(tabView, sessionId) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun onShareTabs() {
|
|
||||||
interactor.onShareTabs()
|
|
||||||
verify { controller.handleShareTabs() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onStartBrowsingClicked() {
|
fun onStartBrowsingClicked() {
|
||||||
interactor.onStartBrowsingClicked()
|
interactor.onStartBrowsingClicked()
|
||||||
|
|
|
@ -1,43 +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.home
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import io.mockk.mockk
|
|
||||||
import kotlinx.android.synthetic.main.tab_list_row.view.*
|
|
||||||
import mozilla.components.browser.state.state.MediaState
|
|
||||||
import mozilla.components.browser.toolbar.MAX_URI_LENGTH
|
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabSessionInteractor
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
|
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
|
||||||
class TabViewHolderTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `extremely long URLs are truncated to prevent slowing down the UI`() {
|
|
||||||
val view = LayoutInflater.from(testContext).inflate(
|
|
||||||
R.layout.tab_list_row, null, false)
|
|
||||||
|
|
||||||
val interactor: TabSessionInteractor = mockk()
|
|
||||||
val tabViewHolder = TabViewHolder(view, interactor)
|
|
||||||
|
|
||||||
val extremelyLongUrl = "m".repeat(MAX_URI_LENGTH + 1)
|
|
||||||
val tab = Tab(
|
|
||||||
sessionId = "123",
|
|
||||||
url = extremelyLongUrl,
|
|
||||||
hostname = extremelyLongUrl,
|
|
||||||
title = "test",
|
|
||||||
mediaState = MediaState.State.NONE)
|
|
||||||
tabViewHolder.bindSession(tab)
|
|
||||||
|
|
||||||
assertEquals("m".repeat(MAX_URI_LENGTH), view.hostname.text)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue