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 {
|
||||
Screengrab.screenshot("browser-tab-menu")
|
||||
}.closeBrowserMenuToBrowser {
|
||||
}.openHomeScreen {
|
||||
Screengrab.screenshot("homescree-with-tabs")
|
||||
}.openTabDrawer {
|
||||
Screengrab.screenshot("tab-drawer-with-tabs")
|
||||
closeTab()
|
||||
Screengrab.screenshot("remove-tab")
|
||||
}
|
||||
|
|
|
@ -234,8 +234,8 @@ class BookmarksTest {
|
|||
}.openThreeDotMenu(defaultWebPage.url) {
|
||||
}.clickOpenInNewTab {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
}.openHomeScreen {
|
||||
verifyOpenTabsHeader()
|
||||
}.openTabDrawer {
|
||||
verifyNormalModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,8 +253,8 @@ class BookmarksTest {
|
|||
}.openThreeDotMenu(defaultWebPage.url) {
|
||||
}.clickOpenInPrivateTab {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,9 +327,9 @@ class BookmarksTest {
|
|||
|
||||
browserScreen {
|
||||
createBookmark(defaultWebPage.url)
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
closeTab()
|
||||
}.openThreeDotMenu {
|
||||
}.openHomeScreen { }.openThreeDotMenu {
|
||||
}.openBookmarks {
|
||||
bookmarksListIdlingResource =
|
||||
RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.bookmark_list))
|
||||
|
@ -340,9 +340,9 @@ class BookmarksTest {
|
|||
}
|
||||
|
||||
multipleSelectionToolbar {
|
||||
}.clickOpenNewTab {
|
||||
}.clickOpenNewTab { }.openTabDrawer {
|
||||
verifyNormalModeSelected()
|
||||
verifyExistingTabList()
|
||||
verifyOpenTabsHeader()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,9 +363,9 @@ class BookmarksTest {
|
|||
}
|
||||
|
||||
multipleSelectionToolbar {
|
||||
}.clickOpenPrivateTab {
|
||||
}.clickOpenPrivateTab { }.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
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")
|
||||
snackBarButtonClick("Switch")
|
||||
verifyUrl(genericURL.url.toString())
|
||||
}.openHomeScreen {
|
||||
verifyHomeScreen()
|
||||
}.openTabDrawer {
|
||||
verifyExistingOpenTabs("Test_Page_1")
|
||||
verifyExistingOpenTabs("Test_Page_4")
|
||||
}
|
||||
|
@ -93,8 +92,8 @@ class ContextMenusTest {
|
|||
verifySnackBarText("New private tab opened")
|
||||
snackBarButtonClick("Switch")
|
||||
verifyUrl(genericURL.url.toString())
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
verifyExistingOpenTabs("Test_Page_2")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ class HistoryTest {
|
|||
// Clearing all history data after each test to avoid overlapping data
|
||||
val applicationContext: Context = activityTestRule.activity.applicationContext
|
||||
val historyStorage = PlacesHistoryStorage(applicationContext)
|
||||
|
||||
runBlocking {
|
||||
historyStorage.deleteEverything()
|
||||
}
|
||||
|
@ -124,8 +125,8 @@ class HistoryTest {
|
|||
}.openThreeDotMenu {
|
||||
}.clickOpenInNormalTab {
|
||||
verifyPageContent(firstWebPage.content)
|
||||
}.openHomeScreen {
|
||||
verifyOpenTabsHeader()
|
||||
}.openTabDrawer {
|
||||
verifyNormalModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,8 +142,8 @@ class HistoryTest {
|
|||
}.openThreeDotMenu {
|
||||
}.clickOpenInPrivateTab {
|
||||
verifyPageContent(firstWebPage.content)
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,18 +207,18 @@ class HistoryTest {
|
|||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||
verifyPageContent("Page content: 1")
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
closeTab()
|
||||
}.openThreeDotMenu {
|
||||
}.openHomeScreen { }.openThreeDotMenu {
|
||||
}.openHistory {
|
||||
longTapSelectItem(firstWebPage.url)
|
||||
openActionBarOverflowOrOptionsMenu(activityTestRule.activity)
|
||||
}
|
||||
|
||||
multipleSelectionToolbar {
|
||||
}.clickOpenNewTab {
|
||||
}.clickOpenNewTab { }.openTabDrawer {
|
||||
verifyExistingTabList()
|
||||
verifyOpenTabsHeader()
|
||||
verifyNormalModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,9 +236,9 @@ class HistoryTest {
|
|||
}
|
||||
|
||||
multipleSelectionToolbar {
|
||||
}.clickOpenPrivateTab {
|
||||
}.clickOpenPrivateTab { }.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
verifyExistingTabList()
|
||||
verifyPrivateSessionHeader()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +250,7 @@ class HistoryTest {
|
|||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(firstWebPage.url) {
|
||||
verifyPageContent("Page content: 1")
|
||||
}.openHomeScreen {}
|
||||
}.openTabDrawer { }.openHomeScreen { }
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(secondWebPage.url) {
|
||||
|
|
|
@ -41,13 +41,8 @@ class HomeScreenTest {
|
|||
verifyHomePrivateBrowsingButton()
|
||||
verifyHomeMenu()
|
||||
verifyHomeWordmark()
|
||||
verifyOpenTabsHeader()
|
||||
verifyAddTabButton()
|
||||
verifyNoTabsOpenedHeader()
|
||||
verifyNoTabsOpenedText()
|
||||
verifyCollectionsHeaderIsNotShown()
|
||||
verifyNoCollectionsHeaderIsNotShown()
|
||||
verifyNoCollectionsTextIsNotShown()
|
||||
verifyTabButton()
|
||||
verifyCollectionsHeader()
|
||||
verifyHomeToolbar()
|
||||
verifyHomeComponent()
|
||||
|
||||
|
@ -132,10 +127,8 @@ class HomeScreenTest {
|
|||
verifyHomePrivateBrowsingButton()
|
||||
verifyHomeMenu()
|
||||
verifyHomeWordmark()
|
||||
verifyAddTabButton()
|
||||
verifyShareTabsButton(visible = false)
|
||||
verifyPrivateSessionHeader()
|
||||
verifyPrivateSessionMessage(visible = true)
|
||||
verifyTabButton()
|
||||
verifyPrivateSessionMessage()
|
||||
verifyHomeToolbar()
|
||||
verifyHomeComponent()
|
||||
}.openCommonMythsLink {
|
||||
|
@ -152,10 +145,8 @@ class HomeScreenTest {
|
|||
verifyHomePrivateBrowsingButton()
|
||||
verifyHomeMenu()
|
||||
verifyHomeWordmark()
|
||||
verifyAddTabButton()
|
||||
verifyShareTabsButton(visible = true)
|
||||
verifyPrivateSessionHeader()
|
||||
verifyPrivateSessionMessage(visible = false)
|
||||
verifyTabButton()
|
||||
verifyPrivateSessionMessage()
|
||||
verifyHomeToolbar()
|
||||
verifyHomeComponent()
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ class MediaNotificationTest {
|
|||
|
||||
browserScreen {
|
||||
verifyMediaIsPaused()
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
closeTab()
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ class MediaNotificationTest {
|
|||
|
||||
browserScreen {
|
||||
verifyMediaIsPaused()
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
closeTab()
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ class MediaNotificationTest {
|
|||
clickMediaPlayerPlayButton()
|
||||
waitForPlaybackToStart()
|
||||
verifyPageContent("Media file is playing")
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
verifyTabMediaControlButtonState("Pause")
|
||||
clickTabMediaControlButton()
|
||||
verifyTabMediaControlButtonState("Play")
|
||||
|
@ -160,9 +160,9 @@ class MediaNotificationTest {
|
|||
|
||||
browserScreen {
|
||||
verifyMediaIsPaused()
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
closeTab()
|
||||
}
|
||||
}.openHomeScreen { }
|
||||
|
||||
mDevice.openNotification()
|
||||
|
||||
|
|
|
@ -197,6 +197,7 @@ class SettingsBasicsTest {
|
|||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(webpage) {
|
||||
checkTextSizeOnWebsite(textSizePercentage, fenixApp.components)
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
|
|
|
@ -191,6 +191,7 @@ class SettingsPrivacyTest {
|
|||
verifySaveLoginPromptIsShown()
|
||||
// Click save to save the login
|
||||
saveLoginFromPrompt("Save")
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
|
@ -215,6 +216,7 @@ class SettingsPrivacyTest {
|
|||
verifySaveLoginPromptIsShown()
|
||||
// Don't save the login
|
||||
saveLoginFromPrompt("Don’t save")
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
|
@ -264,17 +266,17 @@ class SettingsPrivacyTest {
|
|||
openAppFromExternalLink(defaultWebPage.url.toString())
|
||||
|
||||
browserScreen {
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
}.openHomeScreen { }
|
||||
|
||||
setOpenLinksInPrivateOff()
|
||||
|
||||
openAppFromExternalLink(defaultWebPage.url.toString())
|
||||
|
||||
browserScreen {
|
||||
}.openHomeScreen {
|
||||
verifyOpenTabsHeader()
|
||||
}.openTabDrawer {
|
||||
verifyNormalModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,8 +295,8 @@ class SettingsPrivacyTest {
|
|||
clickAddShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut(pageShortcutName) {
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +314,8 @@ class SettingsPrivacyTest {
|
|||
clickAddShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut(pageShortcutName) {
|
||||
}.openHomeScreen {}
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen { }
|
||||
|
||||
setOpenLinksInPrivateOff()
|
||||
restartApp(activityTestRule)
|
||||
|
@ -320,14 +323,14 @@ class SettingsPrivacyTest {
|
|||
|
||||
addToHomeScreen {
|
||||
}.searchAndOpenHomeScreenShortcut(pageShortcutName) {
|
||||
}.openTabDrawer {
|
||||
verifyNormalModeSelected()
|
||||
}.openHomeScreen {
|
||||
verifyOpenTabsHeader()
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openPrivateBrowsingSubMenu {
|
||||
verifyOpenLinksInPrivateTabOff()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -341,8 +344,8 @@ class SettingsPrivacyTest {
|
|||
}.openPrivateBrowsingShortcut {
|
||||
verifySearchView()
|
||||
}.openBrowser {
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
package org.mozilla.fenix.ui
|
||||
|
||||
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
|
||||
|
@ -18,7 +16,6 @@ import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
|||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
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.navigationToolbar
|
||||
import org.mozilla.fenix.ui.robots.notificationShade
|
||||
|
@ -32,7 +29,7 @@ import org.mozilla.fenix.ui.robots.notificationShade
|
|||
* - Verifying tab list
|
||||
* - Closing all tabs
|
||||
* - Close tab
|
||||
* - Swipe to close tab
|
||||
* - Swipe to close tab (temporarily disabled)
|
||||
* - Undo close tab
|
||||
* - Close private tabs persistent notification
|
||||
*
|
||||
|
@ -65,31 +62,12 @@ class TabbedBrowsingTest {
|
|||
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
|
||||
homeScreen {
|
||||
verifyOpenTabsHeader()
|
||||
verifyNoTabsOpenedText()
|
||||
verifyNoTabsOpenedHeader()
|
||||
verifyNoCollectionsTextIsNotShown()
|
||||
verifyNoCollectionsHeaderIsNotShown()
|
||||
verifyAddTabButton()
|
||||
}
|
||||
|
||||
navigationToolbar {
|
||||
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
verifyTabCounter("1")
|
||||
}.openHomeScreen { }
|
||||
|
||||
homeScreen {
|
||||
// Timing issue on slow devices on Firebase
|
||||
mDevice.waitNotNull(
|
||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||
TestAssetHelper.waitingTime
|
||||
)
|
||||
}.openTabDrawer {
|
||||
verifyExistingTabList()
|
||||
verifyNoCollectionsHeader()
|
||||
verifyNoCollectionsText()
|
||||
|
||||
}.openTabsListThreeDotMenu {
|
||||
verifyCloseAllTabsButton()
|
||||
verifyShareTabButton()
|
||||
|
@ -106,34 +84,20 @@ class TabbedBrowsingTest {
|
|||
homeScreen { }.togglePrivateBrowsingMode()
|
||||
|
||||
homeScreen {
|
||||
verifyPrivateSessionHeader()
|
||||
verifyPrivateSessionMessage(true)
|
||||
verifyAddTabButton()
|
||||
verifyPrivateSessionMessage()
|
||||
verifyTabButton()
|
||||
}
|
||||
|
||||
navigationToolbar {
|
||||
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
verifyTabCounter("1")
|
||||
}.openHomeScreen {
|
||||
// Timing issue on slow devices on Firebase
|
||||
mDevice.waitNotNull(
|
||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||
TestAssetHelper.waitingTime
|
||||
)
|
||||
}.openTabDrawer {
|
||||
verifyExistingTabList()
|
||||
verifyShareTabsButton(true)
|
||||
verifyCloseTabsButton("Test_Page_1")
|
||||
}.togglePrivateBrowsingMode()
|
||||
|
||||
// Verify private tabs remain in private browsing mode
|
||||
|
||||
homeScreen {
|
||||
verifyNoTabsOpenedHeader()
|
||||
verifyNoTabsOpenedText()
|
||||
}.togglePrivateBrowsingMode()
|
||||
|
||||
homeScreen {
|
||||
}.toggleToNormalTabs {
|
||||
verifyNoTabsOpened()
|
||||
}.toggleToPrivateTabs {
|
||||
verifyExistingTabList()
|
||||
}
|
||||
}
|
||||
|
@ -145,24 +109,15 @@ class TabbedBrowsingTest {
|
|||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
}.openHomeScreen { }
|
||||
|
||||
homeScreen {
|
||||
// Timing issue on slow devices on Firebase
|
||||
mDevice.waitNotNull(
|
||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||
TestAssetHelper.waitingTime
|
||||
)
|
||||
}.openTabDrawer {
|
||||
verifyExistingTabList()
|
||||
}.openTabsListThreeDotMenu {
|
||||
verifyCloseAllTabsButton()
|
||||
verifyShareTabButton()
|
||||
verifySaveCollection()
|
||||
}.closeAllTabs {
|
||||
verifyNoCollectionsHeaderIsNotShown()
|
||||
verifyNoCollectionsTextIsNotShown()
|
||||
verifyNoTabsOpenedHeader()
|
||||
verifyNoTabsOpenedText()
|
||||
verifyNoTabsOpened()
|
||||
}.openHomeScreen {
|
||||
}
|
||||
|
||||
// Repeat for Private Tabs
|
||||
|
@ -172,23 +127,20 @@ class TabbedBrowsingTest {
|
|||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
}.openHomeScreen { }
|
||||
|
||||
homeScreen {
|
||||
// Timing issue on slow devices on Firebase
|
||||
mDevice.waitNotNull(
|
||||
Until.findObjects(By.res("org.mozilla.fenix.debug:id/item_tab")),
|
||||
TestAssetHelper.waitingTime
|
||||
)
|
||||
}.openTabDrawer {
|
||||
verifyPrivateModeSelected()
|
||||
verifyExistingTabList()
|
||||
verifyPrivateTabsCloseTabsButton()
|
||||
}.closeAllPrivateTabs {
|
||||
verifyPrivateSessionHeader()
|
||||
verifyPrivateSessionMessage(true)
|
||||
}.openTabsListThreeDotMenu {
|
||||
verifyCloseAllTabsButton()
|
||||
}.closeAllTabs {
|
||||
verifyNoTabsOpened()
|
||||
}.openHomeScreen {
|
||||
verifyPrivateSessionMessage()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("For some reason this intermittently fails with the drawer :(")
|
||||
fun closeTabTest() {
|
||||
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
||||
|
||||
|
@ -196,58 +148,58 @@ class TabbedBrowsingTest {
|
|||
navigationToolbar {
|
||||
}.openNewTabAndEnterToBrowser(element.url) {
|
||||
verifyPageContent(element.content)
|
||||
}.openHomeScreen { }
|
||||
|
||||
homeScreen {
|
||||
}.openTabDrawer {
|
||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||
closeTabViaXButton("Test_Page_${index + 1}")
|
||||
verifySnackBarText("Tab closed")
|
||||
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}")
|
||||
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}")
|
||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||
}.openHomeScreen {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("For some reason this intermittently fails with the drawer :(")
|
||||
fun closePrivateTabTest() {
|
||||
var genericURLS = TestAssetHelper.getGenericAssets(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.togglePrivateBrowsingMode()
|
||||
homeScreen { }.togglePrivateBrowsingMode()
|
||||
genericURLS.forEachIndexed { index, element ->
|
||||
navigationToolbar {
|
||||
}.openNewTabAndEnterToBrowser(element.url) {
|
||||
verifyPageContent(element.content)
|
||||
}.openHomeScreen {
|
||||
}.openTabDrawer {
|
||||
verifyExistingOpenTabs("Test_Page_${index + 1}")
|
||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||
closeTabViaXButton("Test_Page_${index + 1}")
|
||||
verifySnackBarText("Private tab closed")
|
||||
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}")
|
||||
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}")
|
||||
verifyCloseTabsButton("Test_Page_${index + 1}")
|
||||
}.openHomeScreen {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +222,7 @@ class TabbedBrowsingTest {
|
|||
}.clickClosePrivateTabsNotification {
|
||||
// Tap an empty spot on the app homescreen to make sure it's into focus
|
||||
sendSingleTapToScreen(20, 20)
|
||||
verifyPrivateSessionMessage(visible = true)
|
||||
verifyPrivateSessionMessage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,10 +57,12 @@ class ThreeDotMenuMainTest {
|
|||
}.openThreeDotMenu {
|
||||
}.openHelp {
|
||||
verifyHelpUrl()
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openWhatsNew {
|
||||
verifyWhatsNewURL()
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ class TopSitesTest {
|
|||
verifyAddFirefoxHome()
|
||||
}.addToFirefoxHome {
|
||||
verifySnackBarText("Added to top sites!")
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
verifyExistingTabList()
|
||||
verifyExistingTopSitesList()
|
||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||
}
|
||||
|
@ -77,13 +77,14 @@ class TopSitesTest {
|
|||
verifyAddFirefoxHome()
|
||||
}.addToFirefoxHome {
|
||||
verifySnackBarText("Added to top sites!")
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
verifyExistingTabList()
|
||||
verifyExistingTopSitesList()
|
||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||
}.openTopSiteTabWithTitle(title = defaultWebPageTitle) {
|
||||
verifyPageContent(defaultWebPage.content)
|
||||
verifyUrl(defaultWebPage.url.toString().replace("http://", ""))
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
verifyExistingTopSitesList()
|
||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||
|
@ -107,8 +108,8 @@ class TopSitesTest {
|
|||
verifyAddFirefoxHome()
|
||||
}.addToFirefoxHome {
|
||||
verifySnackBarText("Added to top sites!")
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
verifyExistingTabList()
|
||||
verifyExistingTopSitesList()
|
||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||
|
@ -130,8 +131,8 @@ class TopSitesTest {
|
|||
verifyAddFirefoxHome()
|
||||
}.addToFirefoxHome {
|
||||
verifySnackBarText("Added to top sites!")
|
||||
}.openTabDrawer {
|
||||
}.openHomeScreen {
|
||||
verifyExistingTabList()
|
||||
verifyExistingTopSitesList()
|
||||
verifyExistingTopSitesTabs(defaultWebPageTitle)
|
||||
}.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) {
|
||||
|
|
|
@ -335,18 +335,18 @@ class BrowserRobot {
|
|||
return NavigationToolbarRobot.Transition()
|
||||
}
|
||||
|
||||
fun openHomeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||
fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
||||
mDevice.waitForIdle()
|
||||
|
||||
tabsCounter().click()
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
HomeScreenRobot().interact()
|
||||
return HomeScreenRobot.Transition()
|
||||
TabDrawerRobot().interact()
|
||||
return TabDrawerRobot.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.assertion.ViewAssertions.doesNotExist
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||
|
@ -56,16 +55,10 @@ class HomeScreenRobot {
|
|||
fun verifyHomeScreen() = assertHomeScreen()
|
||||
fun verifyHomePrivateBrowsingButton() = assertHomePrivateBrowsingButton()
|
||||
fun verifyHomeMenu() = assertHomeMenu()
|
||||
fun verifyOpenTabsHeader() = assertOpenTabsHeader()
|
||||
fun verifyAddTabButton() = assertAddTabButton()
|
||||
fun verifyNoTabsOpenedText() = assertNoTabsOpenedText()
|
||||
fun verifyTabButton() = assertTabButton()
|
||||
fun verifyCollectionsHeader() = assertCollectionsHeader()
|
||||
fun verifyNoCollectionsHeader() = assertNoCollectionsHeader()
|
||||
fun verifyNoCollectionsText() = assertNoCollectionsText()
|
||||
fun verifyNoCollectionsHeaderIsNotShown() = assertNoCollectionsHeaderIsNotVisible()
|
||||
fun verifyCollectionsHeaderIsNotShown() = assertCollectionsHeaderIsNotVisible()
|
||||
fun verifyNoCollectionsTextIsNotShown() = assertNoCollectionsTextIsNotVisible()
|
||||
fun verifyNoTabsOpenedHeader() = assertNoTabsOpenedHeader()
|
||||
fun verifyHomeWordmark() = assertHomeWordmark()
|
||||
fun verifyHomeToolbar() = assertHomeToolbar()
|
||||
fun verifyHomeComponent() = assertHomeComponent()
|
||||
|
@ -110,17 +103,7 @@ class HomeScreenRobot {
|
|||
fun verifyPrivacyNoticeButton() = assertPrivacyNoticeButton()
|
||||
fun verifyStartBrowsingButton() = assertStartBrowsingButton()
|
||||
|
||||
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
|
||||
|
||||
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 verifyPrivateSessionMessage() = assertPrivateSessionMessage()
|
||||
|
||||
fun verifyExistingTopSitesList() = assertExistingTopSitesList()
|
||||
fun verifyNotExistingTopSitesList(title: String) = assertNotExistingTopSitesList(title)
|
||||
|
@ -337,8 +320,6 @@ class HomeScreenRobot {
|
|||
fun swipeTabLeft(title: String) =
|
||||
tab(title).perform(ViewActions.swipeLeft())
|
||||
|
||||
fun closeTabViaXButton(title: String) = closeTabViaX(title)
|
||||
|
||||
fun verifySnackBarText(expectedText: String) {
|
||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
mDevice.waitNotNull(findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
|
||||
|
@ -368,6 +349,20 @@ class HomeScreenRobot {
|
|||
class Transition {
|
||||
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 {
|
||||
threeDotButton().perform(click())
|
||||
|
||||
|
@ -392,7 +387,7 @@ class HomeScreenRobot {
|
|||
}
|
||||
|
||||
fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
|
||||
tabsListThreeDotButton().perform(click())
|
||||
// tabsListThreeDotButton().perform(click())
|
||||
|
||||
ThreeDotMenuMainRobot().interact()
|
||||
return ThreeDotMenuMainRobot.Transition()
|
||||
|
@ -510,23 +505,10 @@ private fun assertHomeWordmark() = onView(ViewMatchers.withResourceName("wordmar
|
|||
private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"))
|
||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||
|
||||
private fun assertOpenTabsHeader() =
|
||||
onView(allOf(withText("Open tabs")))
|
||||
private fun assertTabButton() =
|
||||
onView(allOf(withId(R.id.tab_button), isDisplayed()))
|
||||
.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() =
|
||||
onView(allOf(withText("Collections")))
|
||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||
|
@ -535,14 +517,6 @@ private fun assertNoCollectionsHeader() =
|
|||
onView(allOf(withText("No collections")))
|
||||
.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() =
|
||||
onView(
|
||||
allOf(
|
||||
|
@ -551,14 +525,6 @@ private fun assertNoCollectionsText() =
|
|||
)
|
||||
.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() =
|
||||
onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
|
||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||
|
@ -696,58 +662,16 @@ private fun assertTakePositionBottomRadioButton() =
|
|||
onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button"))
|
||||
.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 =
|
||||
"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" +
|
||||
" service provider, it makes it easier to keep what you do online private from anyone" +
|
||||
" else who uses this device."
|
||||
|
||||
private fun assertPrivateSessionMessage(visible: Boolean) =
|
||||
private fun assertPrivateSessionMessage() =
|
||||
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)))
|
||||
|
||||
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() =
|
||||
onView(allOf(withId(R.id.collection_overflow_button)))
|
||||
|
||||
|
@ -757,18 +681,6 @@ private fun collectionNameTextField() =
|
|||
private fun collectionTitle(title: String) =
|
||||
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() =
|
||||
onView(allOf(withId(R.id.top_sites_list)))
|
||||
.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 tabsCounter() = onView(withId(R.id.tab_button))
|
||||
|
||||
private fun tab(title: String) =
|
||||
onView(
|
||||
|
|
|
@ -87,7 +87,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
|
|||
|
||||
fun clickOpenNewTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||
openInNewTabButton().click()
|
||||
mDevice.waitNotNull(Until.findObject(By.text("Open tabs")), waitingTime)
|
||||
mDevice.waitNotNull(Until.findObject(By.text("Collections")), waitingTime)
|
||||
|
||||
HomeScreenRobot().interact()
|
||||
return HomeScreenRobot.Transition()
|
||||
|
@ -96,7 +96,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
|
|||
fun clickOpenPrivateTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||
openInPrivateTabButton().click()
|
||||
mDevice.waitNotNull(
|
||||
Until.findObject(By.text("Private tabs")),
|
||||
Until.findObject(By.text(PRIVATE_SESSION_MESSAGE)),
|
||||
waitingTime
|
||||
)
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ import androidx.test.espresso.action.ViewActions.typeText
|
|||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
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.withId
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
|
@ -100,8 +99,9 @@ class NavigationToolbarRobot {
|
|||
interact: BrowserRobot.() -> Unit
|
||||
): BrowserRobot.Transition {
|
||||
sessionLoadedIdlingResource = SessionLoadedIdlingResource()
|
||||
mDevice.waitNotNull(Until.findObject(By.descContains("Add tab")), waitingTime)
|
||||
newTab().click()
|
||||
mDevice.waitNotNull(Until.findObject(By.res("org.mozilla.fenix.debug:id/toolbar")), waitingTime)
|
||||
|
||||
urlBar().click()
|
||||
awesomeBar().perform(replaceText(url.toString()), pressImeActionButton())
|
||||
|
||||
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 awesomeBar() = onView(withId(R.id.mozac_browser_toolbar_edit_url_view))
|
||||
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 clearAddressBar() = onView(withId(R.id.mozac_browser_toolbar_clear_view))
|
||||
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.matches
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.matcher.RootMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.Visibility
|
||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||
|
@ -186,12 +187,12 @@ class ThreeDotMenuMainRobot {
|
|||
return BrowserRobot.Transition()
|
||||
}
|
||||
|
||||
fun closeAllTabs(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||
mDevice.waitNotNull(Until.findObject(By.text("Close all tabs")), waitingTime)
|
||||
fun closeAllTabs(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
||||
// mDevice.waitNotNull(Until.findObject(By.text("Close all tabs")), waitingTime)
|
||||
closeAllTabsButton().click()
|
||||
|
||||
HomeScreenRobot().interact()
|
||||
return HomeScreenRobot.Transition()
|
||||
TabDrawerRobot().interact()
|
||||
return TabDrawerRobot.Transition()
|
||||
}
|
||||
|
||||
fun openFindInPage(interact: FindInPageRobot.() -> Unit): FindInPageRobot.Transition {
|
||||
|
@ -313,11 +314,11 @@ private fun refreshButton() = onView(ViewMatchers.withContentDescription("Refres
|
|||
private fun assertRefreshButton() = refreshButton()
|
||||
.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()
|
||||
.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()
|
||||
.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()
|
||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ import androidx.annotation.VisibleForTesting
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import org.mozilla.fenix.components.Analytics
|
||||
import org.mozilla.fenix.components.TabCollectionStorage
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.home.Tab
|
||||
import org.mozilla.fenix.home.toSessionBundle
|
||||
|
||||
interface CollectionCreationController {
|
||||
|
||||
|
@ -58,6 +58,10 @@ interface CollectionCreationController {
|
|||
fun removeTabFromSelection(tab: Tab)
|
||||
}
|
||||
|
||||
fun List<Tab>.toSessionBundle(sessionManager: SessionManager): List<Session> {
|
||||
return this.mapNotNull { sessionManager.findSessionById(it.sessionId) }
|
||||
}
|
||||
|
||||
class DefaultCollectionCreationController(
|
||||
private val store: CollectionCreationStore,
|
||||
private val dismiss: () -> Unit,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package org.mozilla.fenix.components
|
||||
|
||||
import GeckoProvider
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import io.sentry.Sentry
|
||||
|
@ -136,11 +135,6 @@ class Core(private val context: Context) {
|
|||
*/
|
||||
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
|
||||
* 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
|
||||
// the app is used.
|
||||
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.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.appservices.places.BookmarkRoot
|
||||
import mozilla.components.browser.session.Session
|
||||
|
@ -122,8 +121,7 @@ class DefaultBrowserToolbarController(
|
|||
}
|
||||
|
||||
override fun handleTabCounterClick() {
|
||||
sharedViewModel.shouldScrollToSelectedTab = true
|
||||
animateTabAndNavigateHome()
|
||||
onTabCounterClicked.invoke()
|
||||
}
|
||||
|
||||
override fun handleBrowserMenuDismissed(lowPrioHighlightItems: List<ToolbarMenu.Item>) {
|
||||
|
@ -132,7 +130,8 @@ class DefaultBrowserToolbarController(
|
|||
ToolbarMenu.Item.AddToHomeScreen -> activity.settings().installPwaOpened = true
|
||||
is ToolbarMenu.Item.ReaderMode -> activity.settings().readerModeOpened = true
|
||||
ToolbarMenu.Item.OpenInApp -> activity.settings().openInAppOpened = true
|
||||
else -> { }
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +157,9 @@ class DefaultBrowserToolbarController(
|
|||
}
|
||||
ToolbarMenu.Item.SyncedTabs -> {
|
||||
navController.nav(
|
||||
R.id.browserFragment, BrowserFragmentDirections.actionBrowserFragmentToSyncedTabsFragment())
|
||||
R.id.browserFragment,
|
||||
BrowserFragmentDirections.actionBrowserFragmentToSyncedTabsFragment()
|
||||
)
|
||||
}
|
||||
is ToolbarMenu.Item.RequestDesktop -> sessionUseCases.requestDesktopSite.invoke(
|
||||
item.isChecked,
|
||||
|
@ -315,23 +316,11 @@ class DefaultBrowserToolbarController(
|
|||
}
|
||||
}
|
||||
|
||||
private fun animateTabAndNavigateHome() {
|
||||
if (activity.settings().useNewTabTray) {
|
||||
onTabCounterClicked.invoke()
|
||||
return
|
||||
}
|
||||
|
||||
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()
|
||||
)
|
||||
}
|
||||
private fun reportSiteIssue(reportUrl: String, private: Boolean) {
|
||||
if (private) {
|
||||
activity.components.useCases.tabsUseCases.addPrivateTab.invoke(reportUrl)
|
||||
} else {
|
||||
activity.components.useCases.tabsUseCases.addTab.invoke(reportUrl)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,15 +27,11 @@ import androidx.constraintlayout.widget.ConstraintSet.TOP
|
|||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.doOnLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
|
@ -46,34 +42,27 @@ import com.google.android.material.appbar.AppBarLayout
|
|||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.appservices.places.BookmarkRoot
|
||||
import mozilla.components.browser.menu.view.MenuButton
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.browser.state.state.MediaState.State.PLAYING
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.browser.state.selector.normalTabs
|
||||
import mozilla.components.browser.state.selector.privateTabs
|
||||
import mozilla.components.concept.sync.AccountObserver
|
||||
import mozilla.components.concept.sync.AuthType
|
||||
import mozilla.components.concept.sync.OAuthAccount
|
||||
import mozilla.components.feature.media.ext.pauseIfPlaying
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import mozilla.components.feature.top.sites.TopSite
|
||||
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.kotlinx.coroutines.flow.ifChanged
|
||||
import org.mozilla.fenix.BrowserDirection
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.addons.runIfFragmentIsAttached
|
||||
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||
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.settings
|
||||
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.SessionControlAdapter
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlView
|
||||
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.theme.ThemeManager
|
||||
import org.mozilla.fenix.utils.FragmentPreDrawManager
|
||||
import org.mozilla.fenix.utils.allowUndo
|
||||
import org.mozilla.fenix.whatsnew.WhatsNew
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.math.abs
|
||||
|
@ -118,8 +104,6 @@ class HomeFragment : Fragment() {
|
|||
ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
|
||||
}
|
||||
|
||||
private val sharedViewModel: SharedViewModel by activityViewModels()
|
||||
|
||||
private val snackbarAnchorView: View?
|
||||
get() {
|
||||
return if (requireContext().settings().shouldUseBottomToolbar) {
|
||||
|
@ -131,11 +115,6 @@ class HomeFragment : Fragment() {
|
|||
|
||||
private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager
|
||||
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 {
|
||||
override fun onCollectionCreated(title: String, sessions: List<Session>) {
|
||||
|
@ -154,11 +133,6 @@ class HomeFragment : Fragment() {
|
|||
private val sessionManager: 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 val onboarding by lazy { FenixOnboarding(requireContext()) }
|
||||
private lateinit var homeFragmentStore: HomeFragmentStore
|
||||
|
@ -185,16 +159,6 @@ class HomeFragment : Fragment() {
|
|||
val view = inflater.inflate(R.layout.fragment_home, container, false)
|
||||
val activity = activity as HomeActivity
|
||||
|
||||
val sessionObserver = BrowserSessionsObserver(
|
||||
sessionManager,
|
||||
requireComponents.core.store,
|
||||
singleSessionObserver
|
||||
) {
|
||||
emitSessionChanges()
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycle.addObserver(sessionObserver)
|
||||
|
||||
currentMode = CurrentMode(
|
||||
view.context,
|
||||
onboarding,
|
||||
|
@ -208,7 +172,6 @@ class HomeFragment : Fragment() {
|
|||
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections,
|
||||
expandedCollections = emptySet(),
|
||||
mode = currentMode.getCurrentMode(),
|
||||
tabs = emptyList(),
|
||||
topSites = requireComponents.core.topSiteStorage.cachedTopSites,
|
||||
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
|
||||
)
|
||||
|
@ -217,22 +180,15 @@ class HomeFragment : Fragment() {
|
|||
|
||||
_sessionControlInteractor = SessionControlInteractor(
|
||||
DefaultSessionControlController(
|
||||
store = requireComponents.core.store,
|
||||
activity = activity,
|
||||
fragmentStore = homeFragmentStore,
|
||||
navController = findNavController(),
|
||||
browsingModeManager = browsingModeManager,
|
||||
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
|
||||
closeTab = ::closeTab,
|
||||
closeAllTabs = ::closeAllTabs,
|
||||
getListOfTabs = ::getListOfTabs,
|
||||
hideOnboarding = ::hideOnboardingAndOpenSearch,
|
||||
invokePendingDeleteJobs = ::invokePendingDeleteJobs,
|
||||
registerCollectionStorageObserver = ::registerCollectionStorageObserver,
|
||||
scrollToTheTop = ::scrollToTheTop,
|
||||
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
|
||||
openSettingsScreen = ::openSettingsScreen,
|
||||
openSearchScreen = ::navigateToSearch,
|
||||
openWhatsNewLink = { openInNormalTab(SupportUtils.getWhatsNewUrl(activity)) },
|
||||
openPrivacyNotice = { openInNormalTab(SupportUtils.getMozillaPageUrl(PRIVATE_NOTICE)) },
|
||||
showTabTray = ::openTabTray
|
||||
|
@ -249,10 +205,16 @@ class HomeFragment : Fragment() {
|
|||
|
||||
view.consumeFrom(homeFragmentStore, viewLifecycleOwner) {
|
||||
sessionControlView?.update(it)
|
||||
}
|
||||
|
||||
if (context?.settings()?.useNewTabTray == true) {
|
||||
view.tab_button.setCountWithAnimation(it.tabs.size)
|
||||
view.consumeFrom(requireComponents.core.store, viewLifecycleOwner) {
|
||||
val tabCount = if (currentMode.getCurrentMode() == Mode.Normal) {
|
||||
it.normalTabs.size
|
||||
} else {
|
||||
it.privateTabs.size
|
||||
}
|
||||
|
||||
view.tab_button.setCountWithAnimation(tabCount)
|
||||
}
|
||||
|
||||
return view
|
||||
|
@ -263,9 +225,9 @@ class HomeFragment : Fragment() {
|
|||
|
||||
if (!shouldUseBottomToolbar) {
|
||||
view.toolbarLayout.layoutParams = CoordinatorLayout.LayoutParams(
|
||||
ConstraintLayout.LayoutParams.MATCH_PARENT,
|
||||
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
ConstraintLayout.LayoutParams.MATCH_PARENT,
|
||||
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
.apply {
|
||||
gravity = Gravity.TOP
|
||||
}
|
||||
|
@ -339,26 +301,21 @@ class HomeFragment : Fragment() {
|
|||
|
||||
createHomeMenu(requireContext(), WeakReference(view.menuButton))
|
||||
|
||||
view.menuButton.setColorFilter(ContextCompat.getColor(
|
||||
requireContext(),
|
||||
ThemeManager.resolveAttribute(R.attr.primaryText, requireContext())
|
||||
))
|
||||
view.menuButton.setColorFilter(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
ThemeManager.resolveAttribute(R.attr.primaryText, requireContext())
|
||||
)
|
||||
)
|
||||
|
||||
view.toolbar.compoundDrawablePadding =
|
||||
view.resources.getDimensionPixelSize(R.dimen.search_bar_search_engine_icon_padding)
|
||||
view.toolbar_wrapper.setOnClickListener {
|
||||
invokePendingDeleteJobs()
|
||||
hideOnboardingIfNeeded()
|
||||
navigateToSearch()
|
||||
requireComponents.analytics.metrics.track(Event.SearchBarTapped(Event.SearchBarTapped.Source.HOME))
|
||||
}
|
||||
|
||||
view.add_tab_button.setOnClickListener {
|
||||
invokePendingDeleteJobs()
|
||||
hideOnboardingIfNeeded()
|
||||
navigateToSearch()
|
||||
}
|
||||
|
||||
view.tab_button.setOnClickListener {
|
||||
openTabTray()
|
||||
}
|
||||
|
@ -367,8 +324,6 @@ class HomeFragment : Fragment() {
|
|||
privateBrowsingButton,
|
||||
browsingModeManager
|
||||
) { newMode ->
|
||||
invokePendingDeleteJobs()
|
||||
|
||||
if (newMode == BrowsingMode.Private) {
|
||||
requireContext().settings().incrementNumTimesPrivateModeOpened()
|
||||
}
|
||||
|
@ -408,7 +363,6 @@ class HomeFragment : Fragment() {
|
|||
HomeFragmentAction.Change(
|
||||
collections = components.core.tabCollectionStorage.cachedTabCollections,
|
||||
mode = currentMode.getCurrentMode(),
|
||||
tabs = getListOfSessions().toTabs(),
|
||||
topSites = components.core.topSiteStorage.cachedTopSites,
|
||||
tip = FenixTipManager(listOf(MigrationTipProvider(requireContext()))).getTip()
|
||||
)
|
||||
|
@ -428,7 +382,8 @@ class HomeFragment : Fragment() {
|
|||
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
||||
if (authType != AuthType.Existing) {
|
||||
view?.let {
|
||||
FenixSnackbar.make(view = it,
|
||||
FenixSnackbar.make(
|
||||
view = it,
|
||||
duration = Snackbar.LENGTH_SHORT,
|
||||
isDisplayedWithBrowserToolbar = false
|
||||
)
|
||||
|
@ -451,79 +406,12 @@ class HomeFragment : Fragment() {
|
|||
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) {
|
||||
if (mode != Mode.fromBrowsingMode(browsingModeManager.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) {
|
||||
val context = context ?: return
|
||||
AlertDialog.Builder(context).apply {
|
||||
|
@ -546,7 +434,6 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
override fun onStop() {
|
||||
invokePendingDeleteJobs()
|
||||
super.onStop()
|
||||
val homeViewModel: HomeScreenViewModel by activityViewModels {
|
||||
ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652
|
||||
|
@ -561,17 +448,6 @@ class HomeFragment : Fragment() {
|
|||
activity?.window?.setBackgroundDrawableResource(R.drawable.private_home_background_gradient)
|
||||
}
|
||||
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() {
|
||||
|
@ -631,8 +507,7 @@ class HomeFragment : Fragment() {
|
|||
onboarding.finish()
|
||||
homeFragmentStore.dispatch(
|
||||
HomeFragmentAction.ModeChange(
|
||||
mode = currentMode.getCurrentMode(),
|
||||
tabs = getListOfSessions().toTabs()
|
||||
mode = currentMode.getCurrentMode()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -665,96 +540,91 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
@SuppressWarnings("ComplexMethod", "LongMethod")
|
||||
private fun createHomeMenu(context: Context, menuButtonView: WeakReference<MenuButton>) = HomeMenu(
|
||||
this.viewLifecycleOwner,
|
||||
context,
|
||||
onItemTapped = {
|
||||
when (it) {
|
||||
HomeMenu.Item.Settings -> {
|
||||
invokePendingDeleteJobs()
|
||||
hideOnboardingIfNeeded()
|
||||
nav(
|
||||
R.id.homeFragment,
|
||||
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
|
||||
private fun createHomeMenu(context: Context, menuButtonView: WeakReference<MenuButton>) =
|
||||
HomeMenu(
|
||||
this.viewLifecycleOwner,
|
||||
context,
|
||||
onItemTapped = {
|
||||
when (it) {
|
||||
HomeMenu.Item.Settings -> {
|
||||
hideOnboardingIfNeeded()
|
||||
nav(
|
||||
R.id.homeFragment,
|
||||
HomeFragmentDirections.actionGlobalSettingsFragment()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
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()
|
||||
hideOnboardingIfNeeded()
|
||||
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 }
|
||||
)
|
||||
},
|
||||
onHighlightPresent = { menuButtonView.get()?.setHighlight(it) },
|
||||
onMenuBuilderChanged = { menuButtonView.get()?.menuBuilder = it }
|
||||
)
|
||||
|
||||
private fun subscribeToTabCollections(): 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> {
|
||||
return sessionManager.sessionsOfType(private = private)
|
||||
.filter { session: Session -> session.id != pendingSessionDeletion?.sessionId }
|
||||
.toList()
|
||||
}
|
||||
|
||||
|
@ -874,13 +659,6 @@ class HomeFragment : Fragment() {
|
|||
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
||||
}
|
||||
|
||||
private fun scrollToTheTop() {
|
||||
viewLifecycleOwner.lifecycleScope.launch(Main) {
|
||||
delay(ANIM_SCROLL_DELAY)
|
||||
sessionControlView!!.view.smoothScrollToPosition(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun scrollAndAnimateCollection(
|
||||
tabsAddedToCollectionSize: Int,
|
||||
changedCollection: TabCollection? = null
|
||||
|
@ -968,7 +746,8 @@ class HomeFragment : Fragment() {
|
|||
} else {
|
||||
R.string.create_collection_tab_saved
|
||||
}
|
||||
FenixSnackbar.make(view = view,
|
||||
FenixSnackbar.make(
|
||||
view = view,
|
||||
duration = Snackbar.LENGTH_LONG,
|
||||
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() {
|
||||
invokePendingDeleteJobs()
|
||||
hideOnboardingIfNeeded()
|
||||
TabTrayDialogFragment.show(parentFragmentManager)
|
||||
}
|
||||
|
||||
|
@ -1052,97 +818,8 @@ class HomeFragment : Fragment() {
|
|||
private const val ANIM_SNACKBAR_DELAY = 100L
|
||||
private const val CFR_WIDTH_DIVIDER = 1.7
|
||||
private const val CFR_Y_OFFSET = -20
|
||||
private const val SELECTED_TAB_OFFSET = 20
|
||||
|
||||
// Layout
|
||||
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
|
||||
|
||||
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.feature.tab.collections.TabCollection
|
||||
import mozilla.components.feature.top.sites.TopSite
|
||||
|
@ -34,10 +32,6 @@ data class Tab(
|
|||
val mediaState: MediaState.State
|
||||
)
|
||||
|
||||
fun List<Tab>.toSessionBundle(sessionManager: SessionManager): List<Session> {
|
||||
return this.mapNotNull { sessionManager.findSessionById(it.sessionId) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The state for the [HomeFragment].
|
||||
*
|
||||
|
@ -52,14 +46,12 @@ data class HomeFragmentState(
|
|||
val collections: List<TabCollection>,
|
||||
val expandedCollections: Set<Long>,
|
||||
val mode: Mode,
|
||||
val tabs: List<Tab>,
|
||||
val topSites: List<TopSite>,
|
||||
val tip: Tip? = null
|
||||
) : State
|
||||
|
||||
sealed class HomeFragmentAction : Action {
|
||||
data class Change(
|
||||
val tabs: List<Tab>,
|
||||
val topSites: List<TopSite>,
|
||||
val mode: Mode,
|
||||
val collections: List<TabCollection>,
|
||||
|
@ -71,8 +63,7 @@ sealed class HomeFragmentAction : Action {
|
|||
HomeFragmentAction()
|
||||
|
||||
data class CollectionsChange(val collections: List<TabCollection>) : HomeFragmentAction()
|
||||
data class ModeChange(val mode: Mode, val tabs: List<Tab> = emptyList()) : HomeFragmentAction()
|
||||
data class TabsChange(val tabs: List<Tab>) : HomeFragmentAction()
|
||||
data class ModeChange(val mode: Mode) : HomeFragmentAction()
|
||||
data class TopSitesChange(val topSites: List<TopSite>) : HomeFragmentAction()
|
||||
data class RemoveTip(val tip: Tip) : HomeFragmentAction()
|
||||
}
|
||||
|
@ -85,7 +76,6 @@ private fun homeFragmentStateReducer(
|
|||
is HomeFragmentAction.Change -> state.copy(
|
||||
collections = action.collections,
|
||||
mode = action.mode,
|
||||
tabs = action.tabs,
|
||||
topSites = action.topSites,
|
||||
tip = action.tip
|
||||
)
|
||||
|
@ -101,8 +91,7 @@ private fun homeFragmentStateReducer(
|
|||
state.copy(expandedCollections = newExpandedCollection)
|
||||
}
|
||||
is HomeFragmentAction.CollectionsChange -> state.copy(collections = action.collections)
|
||||
is HomeFragmentAction.ModeChange -> state.copy(mode = action.mode, tabs = action.tabs)
|
||||
is HomeFragmentAction.TabsChange -> state.copy(tabs = action.tabs)
|
||||
is HomeFragmentAction.ModeChange -> state.copy(mode = action.mode)
|
||||
is HomeFragmentAction.TopSitesChange -> state.copy(topSites = action.topSites)
|
||||
is HomeFragmentAction.RemoveTip -> { state.copy(tip = null) }
|
||||
}
|
||||
|
|
|
@ -8,12 +8,6 @@ import androidx.lifecycle.ViewModel
|
|||
import mozilla.components.browser.state.state.content.DownloadState
|
||||
|
||||
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
|
||||
* Format: HashMap<sessionId, Pair<DownloadState, didFail>
|
||||
|
|
|
@ -7,29 +7,21 @@ package org.mozilla.fenix.home.sessioncontrol
|
|||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.tab_list_row.*
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import mozilla.components.feature.top.sites.TopSite
|
||||
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.Tab
|
||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
|
||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
||||
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.SaveTabGroupViewHolder
|
||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder
|
||||
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.onboarding.OnboardingAutomaticSignInViewHolder
|
||||
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) {
|
||||
data class TipItem(val tip: Tip) : AdapterItem(
|
||||
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)
|
||||
|
||||
object SaveTabGroup : AdapterItem(SaveTabGroupViewHolder.LAYOUT_ID)
|
||||
|
||||
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
|
||||
data class NoContentMessage(
|
||||
@StringRes val header: Int,
|
||||
@StringRes val description: Int
|
||||
) : 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)
|
||||
data class CollectionItem(
|
||||
val collection: TabCollection,
|
||||
val expanded: Boolean,
|
||||
val sessionHasOpenTabs: Boolean
|
||||
val expanded: Boolean
|
||||
) : AdapterItem(CollectionViewHolder.LAYOUT_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)
|
||||
return when (viewType) {
|
||||
ButtonTipViewHolder.LAYOUT_ID -> ButtonTipViewHolder(view, interactor)
|
||||
TabHeaderViewHolder.LAYOUT_ID -> TabHeaderViewHolder(view, interactor)
|
||||
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, interactor)
|
||||
TopSiteViewHolder.LAYOUT_ID -> TopSiteViewHolder(view, interactor)
|
||||
SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, interactor)
|
||||
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, interactor)
|
||||
NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view)
|
||||
NoContentMessageWithActionViewHolder.LAYOUT_ID -> NoContentMessageWithActionViewHolder(view)
|
||||
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
|
||||
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor)
|
||||
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, interactor, differentLastItem = true)
|
||||
|
@ -202,28 +152,16 @@ class SessionControlAdapter(
|
|||
val tipItem = item as AdapterItem.TipItem
|
||||
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 -> {
|
||||
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 -> {
|
||||
val (header, description) = item as AdapterItem.NoContentMessage
|
||||
holder.bind(header, description)
|
||||
}
|
||||
is CollectionViewHolder -> {
|
||||
val (collection, expanded, sessionHasOpenTabs) = item as AdapterItem.CollectionItem
|
||||
holder.bindSession(collection, expanded, sessionHasOpenTabs)
|
||||
val (collection, expanded) = item as AdapterItem.CollectionItem
|
||||
holder.bindSession(collection, expanded)
|
||||
}
|
||||
is TabInCollectionViewHolder -> {
|
||||
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
|
||||
|
||||
import android.view.View
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
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.ext.restore
|
||||
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.R
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
||||
import org.mozilla.fenix.collections.SaveCollectionStep
|
||||
import org.mozilla.fenix.components.TabCollectionStorage
|
||||
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.ext.components
|
||||
import org.mozilla.fenix.ext.nav
|
||||
import org.mozilla.fenix.ext.sessionsOfType
|
||||
import org.mozilla.fenix.home.HomeFragment
|
||||
import org.mozilla.fenix.home.HomeFragmentAction
|
||||
import org.mozilla.fenix.home.HomeFragmentDirections
|
||||
import org.mozilla.fenix.home.HomeFragmentStore
|
||||
import org.mozilla.fenix.home.Tab
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.settings.SupportUtils
|
||||
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||
|
||||
|
@ -46,16 +39,6 @@ import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
|||
*/
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
interface SessionControlController {
|
||||
/**
|
||||
* @see [TabSessionInteractor.onCloseTab]
|
||||
*/
|
||||
fun handleCloseTab(sessionId: String)
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onCloseAllTabs]
|
||||
*/
|
||||
fun handleCloseAllTabs(isPrivateMode: Boolean)
|
||||
|
||||
/**
|
||||
* @see [CollectionInteractor.onCollectionAddTabTapped]
|
||||
*/
|
||||
|
@ -91,16 +74,6 @@ interface SessionControlController {
|
|||
*/
|
||||
fun handleOpenInPrivateTabClicked(topSite: TopSite)
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onPauseMediaClicked]
|
||||
*/
|
||||
fun handlePauseMediaClicked()
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onPlayMediaClicked]
|
||||
*/
|
||||
fun handlePlayMediaClicked()
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onPrivateBrowsingLearnMoreClicked]
|
||||
*/
|
||||
|
@ -116,26 +89,11 @@ interface SessionControlController {
|
|||
*/
|
||||
fun handleRenameCollectionTapped(collection: TabCollection)
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onSaveToCollection]
|
||||
*/
|
||||
fun handleSaveTabToCollection(selectedTabId: String?)
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onSelectTab]
|
||||
*/
|
||||
fun handleSelectTab(tabView: View, sessionId: String)
|
||||
|
||||
/**
|
||||
* @see [TopSiteInteractor.onSelectTopSite]
|
||||
*/
|
||||
fun handleSelectTopSite(url: String, isDefault: Boolean)
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onShareTabs]
|
||||
*/
|
||||
fun handleShareTabs()
|
||||
|
||||
/**
|
||||
* @see [OnboardingInteractor.onStartBrowsingClicked]
|
||||
*/
|
||||
|
@ -161,32 +119,20 @@ interface SessionControlController {
|
|||
*/
|
||||
fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean)
|
||||
|
||||
/**
|
||||
* @see [TabSessionInteractor.onOpenNewTabClicked]
|
||||
*/
|
||||
fun handleonOpenNewTabClicked()
|
||||
|
||||
fun handleCloseTip(tip: Tip)
|
||||
}
|
||||
|
||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
||||
class DefaultSessionControlController(
|
||||
private val store: BrowserStore,
|
||||
private val activity: HomeActivity,
|
||||
private val fragmentStore: HomeFragmentStore,
|
||||
private val navController: NavController,
|
||||
private val browsingModeManager: BrowsingModeManager,
|
||||
private val viewLifecycleScope: CoroutineScope,
|
||||
private val closeTab: (sessionId: String) -> Unit,
|
||||
private val closeAllTabs: (isPrivateMode: Boolean) -> Unit,
|
||||
private val getListOfTabs: () -> List<Tab>,
|
||||
private val hideOnboarding: () -> Unit,
|
||||
private val invokePendingDeleteJobs: () -> Unit,
|
||||
private val registerCollectionStorageObserver: () -> Unit,
|
||||
private val scrollToTheTop: () -> Unit,
|
||||
private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit,
|
||||
private val openSettingsScreen: () -> Unit,
|
||||
private val openSearchScreen: () -> Unit,
|
||||
private val openWhatsNewLink: () -> Unit,
|
||||
private val openPrivacyNotice: () -> Unit,
|
||||
private val showTabTray: () -> Unit
|
||||
|
@ -200,14 +146,6 @@ class DefaultSessionControlController(
|
|||
private val topSiteStorage: 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) {
|
||||
metrics.track(Event.CollectionAddTabPressed)
|
||||
showCollectionCreationFragment(
|
||||
|
@ -217,8 +155,6 @@ class DefaultSessionControlController(
|
|||
}
|
||||
|
||||
override fun handleCollectionOpenTabClicked(tab: ComponentTab) {
|
||||
invokePendingDeleteJobs()
|
||||
|
||||
sessionManager.restore(
|
||||
activity,
|
||||
activity.components.core.engine,
|
||||
|
@ -239,8 +175,6 @@ class DefaultSessionControlController(
|
|||
}
|
||||
|
||||
override fun handleCollectionOpenTabsTapped(collection: TabCollection) {
|
||||
invokePendingDeleteJobs()
|
||||
|
||||
sessionManager.restore(
|
||||
activity,
|
||||
activity.components.core.engine,
|
||||
|
@ -250,12 +184,7 @@ class DefaultSessionControlController(
|
|||
}
|
||||
)
|
||||
|
||||
if (activity.settings().useNewTabTray) {
|
||||
showTabTray()
|
||||
} else {
|
||||
scrollToTheTop()
|
||||
}
|
||||
|
||||
showTabTray()
|
||||
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() {
|
||||
activity.openToBrowserAndLoad(
|
||||
searchTermOrURL = SupportUtils.getGenericSumoURLForTopic
|
||||
|
@ -324,35 +245,7 @@ class DefaultSessionControlController(
|
|||
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) {
|
||||
invokePendingDeleteJobs()
|
||||
metrics.track(Event.TopSiteOpenInNewTab)
|
||||
if (isDefault) { metrics.track(Event.TopSiteOpenDefault) }
|
||||
if (url == SupportUtils.POCKET_TRENDING_URL) { metrics.track(Event.PocketTopSiteClicked) }
|
||||
|
@ -364,15 +257,6 @@ class DefaultSessionControlController(
|
|||
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() {
|
||||
hideOnboarding()
|
||||
}
|
||||
|
@ -393,10 +277,6 @@ class DefaultSessionControlController(
|
|||
fragmentStore.dispatch(HomeFragmentAction.CollectionExpanded(collection, expand))
|
||||
}
|
||||
|
||||
override fun handleonOpenNewTabClicked() {
|
||||
openSearchScreen()
|
||||
}
|
||||
|
||||
override fun handleCloseTip(tip: Tip) {
|
||||
fragmentStore.dispatch(HomeFragmentAction.RemoveTip(tip))
|
||||
}
|
||||
|
@ -427,8 +307,4 @@ class DefaultSessionControlController(
|
|||
)
|
||||
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
|
||||
|
||||
import android.view.View
|
||||
import mozilla.components.feature.tab.collections.Tab
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import mozilla.components.feature.top.sites.TopSite
|
||||
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].
|
||||
*/
|
||||
|
@ -112,72 +122,6 @@ interface TipInteractor {
|
|||
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].
|
||||
*/
|
||||
|
@ -214,15 +158,7 @@ interface TopSiteInteractor {
|
|||
@SuppressWarnings("TooManyFunctions")
|
||||
class SessionControlInteractor(
|
||||
private val controller: SessionControlController
|
||||
) : CollectionInteractor, OnboardingInteractor, TabSessionInteractor, TopSiteInteractor, TipInteractor {
|
||||
override fun onCloseTab(sessionId: String) {
|
||||
controller.handleCloseTab(sessionId)
|
||||
}
|
||||
|
||||
override fun onCloseAllTabs(isPrivateMode: Boolean) {
|
||||
controller.handleCloseAllTabs(isPrivateMode)
|
||||
}
|
||||
|
||||
) : CollectionInteractor, OnboardingInteractor, TopSiteInteractor, TipInteractor, TabSessionInteractor {
|
||||
override fun onCollectionAddTabTapped(collection: TabCollection) {
|
||||
controller.handleCollectionAddTabTapped(collection)
|
||||
}
|
||||
|
@ -251,18 +187,6 @@ class SessionControlInteractor(
|
|||
controller.handleOpenInPrivateTabClicked(topSite)
|
||||
}
|
||||
|
||||
override fun onPauseMediaClicked() {
|
||||
controller.handlePauseMediaClicked()
|
||||
}
|
||||
|
||||
override fun onPlayMediaClicked() {
|
||||
controller.handlePlayMediaClicked()
|
||||
}
|
||||
|
||||
override fun onPrivateBrowsingLearnMoreClicked() {
|
||||
controller.handlePrivateBrowsingLearnMoreClicked()
|
||||
}
|
||||
|
||||
override fun onRemoveTopSiteClicked(topSite: TopSite) {
|
||||
controller.handleRemoveTopSiteClicked(topSite)
|
||||
}
|
||||
|
@ -271,22 +195,10 @@ class SessionControlInteractor(
|
|||
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) {
|
||||
controller.handleSelectTopSite(url, isDefault)
|
||||
}
|
||||
|
||||
override fun onShareTabs() {
|
||||
controller.handleShareTabs()
|
||||
}
|
||||
|
||||
override fun onStartBrowsingClicked() {
|
||||
controller.handleStartBrowsingClicked()
|
||||
}
|
||||
|
@ -307,11 +219,11 @@ class SessionControlInteractor(
|
|||
controller.handleToggleCollectionExpanded(collection, expand)
|
||||
}
|
||||
|
||||
override fun onOpenNewTabClicked() {
|
||||
controller.handleonOpenNewTabClicked()
|
||||
}
|
||||
|
||||
override fun onCloseTip(tip: Tip) {
|
||||
controller.handleCloseTip(tip)
|
||||
}
|
||||
|
||||
override fun onPrivateBrowsingLearnMoreClicked() {
|
||||
controller.handlePrivateBrowsingLearnMoreClicked()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package org.mozilla.fenix.home.sessioncontrol
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
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.Mode
|
||||
import org.mozilla.fenix.home.OnboardingState
|
||||
import org.mozilla.fenix.home.Tab
|
||||
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(
|
||||
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.
|
||||
@SuppressWarnings("LongParameterList", "ComplexMethod")
|
||||
private fun normalModeAdapterItems(
|
||||
context: Context,
|
||||
tabs: List<Tab>,
|
||||
topSites: List<TopSite>,
|
||||
collections: List<TabCollection>,
|
||||
expandedCollections: Set<Long>,
|
||||
|
@ -54,60 +42,25 @@ private fun normalModeAdapterItems(
|
|||
items.add(AdapterItem.TopSiteList(topSites))
|
||||
}
|
||||
|
||||
val useNewTabTray = context.settings().useNewTabTray
|
||||
|
||||
if (!useNewTabTray) {
|
||||
items.add(AdapterItem.TabHeader(false, tabs.isNotEmpty()))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if (collections.isEmpty()) {
|
||||
items.add(AdapterItem.CollectionHeader)
|
||||
items.add(noCollectionMessage)
|
||||
} else {
|
||||
showCollections(collections, expandedCollections, 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(
|
||||
collections: List<TabCollection>,
|
||||
expandedCollections: Set<Long>,
|
||||
tabs: List<Tab>,
|
||||
items: MutableList<AdapterItem>
|
||||
) {
|
||||
// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
|
||||
items.add(AdapterItem.CollectionHeader)
|
||||
collections.map {
|
||||
AdapterItem.CollectionItem(it, expandedCollections.contains(it.id), tabs.isNotEmpty())
|
||||
AdapterItem.CollectionItem(it, expandedCollections.contains(it.id))
|
||||
}.forEach {
|
||||
items.add(it)
|
||||
if (it.expanded) {
|
||||
|
@ -116,25 +69,7 @@ private fun showCollections(
|
|||
}
|
||||
}
|
||||
|
||||
private fun privateModeAdapterItems(context: Context, tabs: List<Tab>): List<AdapterItem> {
|
||||
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 privateModeAdapterItems() = listOf(AdapterItem.PrivateBrowsingDescription)
|
||||
|
||||
private fun onboardingAdapterItems(onboardingState: OnboardingState): List<AdapterItem> {
|
||||
val items: MutableList<AdapterItem> = mutableListOf(AdapterItem.OnboardingHeader)
|
||||
|
@ -171,9 +106,9 @@ private fun onboardingAdapterItems(onboardingState: OnboardingState): List<Adapt
|
|||
return items
|
||||
}
|
||||
|
||||
private fun HomeFragmentState.toAdapterList(context: Context): List<AdapterItem> = when (mode) {
|
||||
is Mode.Normal -> normalModeAdapterItems(context, tabs, topSites, collections, expandedCollections, tip)
|
||||
is Mode.Private -> privateModeAdapterItems(context, tabs)
|
||||
private fun HomeFragmentState.toAdapterList(): List<AdapterItem> = when (mode) {
|
||||
is Mode.Normal -> normalModeAdapterItems(topSites, collections, expandedCollections, tip)
|
||||
is Mode.Private -> privateModeAdapterItems()
|
||||
is Mode.Onboarding -> onboardingAdapterItems(mode.state)
|
||||
}
|
||||
|
||||
|
@ -212,7 +147,7 @@ class SessionControlView(
|
|||
sessionControlAdapter.submitList(null)
|
||||
}
|
||||
|
||||
val stateAdapterList = state.toAdapterList(view.context)
|
||||
val stateAdapterList = state.toAdapterList()
|
||||
|
||||
if (homeScreenViewModel.shouldScrollToTopSites) {
|
||||
sessionControlAdapter.submitList(stateAdapterList) {
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
|
||||
|
||||
class SwipeToDeleteCallback(
|
||||
val interactor: SessionControlInteractor
|
||||
|
@ -29,7 +28,6 @@ class SwipeToDeleteCallback(
|
|||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
when (viewHolder) {
|
||||
is TabViewHolder -> interactor.onCloseTab(viewHolder.tab?.sessionId!!)
|
||||
is TabInCollectionViewHolder -> {
|
||||
interactor.onCollectionRemoveTab(viewHolder.collection, viewHolder.tab)
|
||||
}
|
||||
|
@ -108,7 +106,7 @@ class SwipeToDeleteCallback(
|
|||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int {
|
||||
return if (recyclerView.hasWindowFocus() &&
|
||||
(viewHolder is TabViewHolder || viewHolder is TabInCollectionViewHolder)
|
||||
viewHolder is TabInCollectionViewHolder
|
||||
) {
|
||||
super.getSwipeDirs(recyclerView, viewHolder)
|
||||
} else 0
|
||||
|
|
|
@ -11,9 +11,11 @@ import androidx.core.graphics.BlendModeCompat.SRC_IN
|
|||
import kotlinx.android.synthetic.main.collection_home_list_row.*
|
||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||
import mozilla.components.browser.state.selector.normalTabs
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.ViewHolder
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.getIconColor
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
import org.mozilla.fenix.ext.removeAndDisable
|
||||
|
@ -29,11 +31,13 @@ class CollectionViewHolder(
|
|||
|
||||
private lateinit var collection: TabCollection
|
||||
private var expanded = false
|
||||
private var sessionHasOpenTabs = false
|
||||
private var collectionMenu: CollectionItemMenu
|
||||
|
||||
init {
|
||||
collectionMenu = CollectionItemMenu(view.context, sessionHasOpenTabs) {
|
||||
collectionMenu = CollectionItemMenu(
|
||||
view.context,
|
||||
{ view.context.components.core.store.state.normalTabs.isNotEmpty() }
|
||||
) {
|
||||
when (it) {
|
||||
is CollectionItemMenu.Item.DeleteCollection -> interactor.onDeleteCollectionTapped(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.expanded = expanded
|
||||
this.sessionHasOpenTabs = sessionHasOpenTabs
|
||||
collectionMenu.sessionHasOpenTabs = sessionHasOpenTabs
|
||||
updateCollectionUI()
|
||||
}
|
||||
|
||||
|
@ -106,7 +108,7 @@ class CollectionViewHolder(
|
|||
|
||||
class CollectionItemMenu(
|
||||
private val context: Context,
|
||||
var sessionHasOpenTabs: Boolean,
|
||||
private val shouldShowAddTab: () -> Boolean,
|
||||
private val onItemTapped: (Item) -> Unit = {}
|
||||
) {
|
||||
sealed class Item {
|
||||
|
@ -136,7 +138,7 @@ class CollectionItemMenu(
|
|||
context.getString(R.string.add_tab)
|
||||
) {
|
||||
onItemTapped.invoke(Item.AddTab)
|
||||
}.apply { visible = { sessionHasOpenTabs } },
|
||||
}.apply { visible = shouldShowAddTab },
|
||||
|
||||
SimpleBrowserMenuItem(
|
||||
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,
|
||||
view.width,
|
||||
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 {
|
||||
const val buttonIncreaseDps = 12
|
||||
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 androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreference
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.getPreferenceKey
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.ext.showToolbar
|
||||
|
||||
/**
|
||||
|
@ -23,13 +20,5 @@ class SecretSettingsPreference : PreferenceFragmentCompat() {
|
|||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
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 org.mozilla.fenix.BuildConfig
|
||||
import org.mozilla.fenix.Config
|
||||
import org.mozilla.fenix.FeatureFlags
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||
import org.mozilla.fenix.components.metrics.MozillaProductDetector
|
||||
|
@ -756,17 +755,6 @@ class Settings private constructor(
|
|||
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(
|
||||
appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy),
|
||||
default = SavedLoginsFragment.SORTING_STRATEGY_ALPHABETICALLY
|
||||
|
|
|
@ -140,26 +140,12 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="start"
|
||||
app:constraint_referenced_ids="tab_button,add_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"/>
|
||||
|
||||
app:constraint_referenced_ids="tab_button" />
|
||||
|
||||
<org.mozilla.fenix.components.toolbar.TabCounter
|
||||
android:id="@+id/tab_button"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toTopOf="@id/bottom_bar"
|
||||
app:layout_constraintBottom_toBottomOf="@id/bottom_bar"
|
||||
app:layout_constraintEnd_toStartOf="@+id/menuButton"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/tab_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="88dp">
|
||||
|
||||
|
|
|
@ -3,10 +3,4 @@
|
|||
- 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/. -->
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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>
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"/>
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package org.mozilla.fenix.home
|
||||
|
||||
import android.view.View
|
||||
import androidx.navigation.NavController
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
@ -17,7 +16,6 @@ import kotlinx.coroutines.newSingleThreadContext
|
|||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.feature.tab.collections.TabCollection
|
||||
import mozilla.components.feature.tabs.TabsUseCases
|
||||
|
@ -26,7 +24,6 @@ import org.junit.Before
|
|||
import org.junit.Test
|
||||
import org.mozilla.fenix.BrowserDirection
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
||||
import org.mozilla.fenix.components.TabCollectionStorage
|
||||
import org.mozilla.fenix.components.metrics.Event
|
||||
import org.mozilla.fenix.components.metrics.MetricController
|
||||
|
@ -39,22 +36,15 @@ import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
|||
class DefaultSessionControlControllerTest {
|
||||
|
||||
private val mainThreadSurrogate = newSingleThreadContext("UI thread")
|
||||
private val store: BrowserStore = mockk(relaxed = true)
|
||||
private val activity: HomeActivity = mockk(relaxed = true)
|
||||
private val fragmentStore: HomeFragmentStore = 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 hideOnboarding: () -> 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 openPrivacyNotice: () -> Unit = mockk(relaxed = true)
|
||||
private val invokePendingDeleteJobs: () -> 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 showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit =
|
||||
mockk(relaxed = true)
|
||||
|
@ -80,26 +70,18 @@ class DefaultSessionControlControllerTest {
|
|||
every { state.collections } returns emptyList()
|
||||
every { state.expandedCollections } returns emptySet()
|
||||
every { state.mode } returns Mode.Normal
|
||||
every { state.tabs } returns emptyList()
|
||||
every { activity.components.analytics.metrics } returns metrics
|
||||
|
||||
controller = DefaultSessionControlController(
|
||||
store = store,
|
||||
activity = activity,
|
||||
fragmentStore = fragmentStore,
|
||||
navController = navController,
|
||||
browsingModeManager = browsingModeManager,
|
||||
viewLifecycleScope = MainScope(),
|
||||
closeTab = closeTab,
|
||||
closeAllTabs = closeAllTabs,
|
||||
getListOfTabs = getListOfTabs,
|
||||
hideOnboarding = hideOnboarding,
|
||||
invokePendingDeleteJobs = invokePendingDeleteJobs,
|
||||
registerCollectionStorageObserver = registerCollectionStorageObserver,
|
||||
scrollToTheTop = scrollToTheTop,
|
||||
showDeleteCollectionPrompt = showDeleteCollectionPrompt,
|
||||
openSettingsScreen = openSettingsScreen,
|
||||
openSearchScreen = openSearchScreen,
|
||||
openWhatsNewLink = openWhatsNewLink,
|
||||
openPrivacyNotice = openPrivacyNotice,
|
||||
showTabTray = showTabTray
|
||||
|
@ -112,20 +94,6 @@ class DefaultSessionControlControllerTest {
|
|||
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
|
||||
fun handleCollectionAddTabTapped() {
|
||||
val collection: TabCollection = mockk(relaxed = true)
|
||||
|
@ -137,7 +105,6 @@ class DefaultSessionControlControllerTest {
|
|||
fun handleCollectionOpenTabClicked() {
|
||||
val tab: ComponentTab = mockk(relaxed = true)
|
||||
controller.handleCollectionOpenTabClicked(tab)
|
||||
verify { invokePendingDeleteJobs() }
|
||||
verify { metrics.track(Event.CollectionTabRestored) }
|
||||
}
|
||||
|
||||
|
@ -145,8 +112,6 @@ class DefaultSessionControlControllerTest {
|
|||
fun handleCollectionOpenTabsTapped() {
|
||||
val collection: TabCollection = mockk(relaxed = true)
|
||||
controller.handleCollectionOpenTabsTapped(collection)
|
||||
verify { invokePendingDeleteJobs() }
|
||||
verify { scrollToTheTop() }
|
||||
verify { metrics.track(Event.CollectionAllTabsRestored) }
|
||||
}
|
||||
|
||||
|
@ -192,27 +157,11 @@ class DefaultSessionControlControllerTest {
|
|||
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
|
||||
fun handleSelectDefaultTopSite() {
|
||||
val topSiteUrl = "mozilla.org"
|
||||
|
||||
controller.handleSelectTopSite(topSiteUrl, true)
|
||||
verify { invokePendingDeleteJobs() }
|
||||
verify { metrics.track(Event.TopSiteOpenInNewTab) }
|
||||
verify { metrics.track(Event.TopSiteOpenDefault) }
|
||||
verify { tabsUseCases.addTab.invoke(
|
||||
|
@ -228,7 +177,6 @@ class DefaultSessionControlControllerTest {
|
|||
val topSiteUrl = "mozilla.org"
|
||||
|
||||
controller.handleSelectTopSite(topSiteUrl, false)
|
||||
verify { invokePendingDeleteJobs() }
|
||||
verify { metrics.track(Event.TopSiteOpenInNewTab) }
|
||||
verify { tabsUseCases.addTab.invoke(
|
||||
topSiteUrl,
|
||||
|
@ -238,12 +186,6 @@ class DefaultSessionControlControllerTest {
|
|||
verify { activity.openToBrowser(BrowserDirection.FromHome) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun handleShareTabs() {
|
||||
controller.handleShareTabs()
|
||||
verify { invokePendingDeleteJobs() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun handleStartBrowsingClicked() {
|
||||
controller.handleStartBrowsingClicked()
|
||||
|
|
|
@ -53,7 +53,6 @@ class HomeFragmentStoreTest {
|
|||
collections = emptyList(),
|
||||
expandedCollections = emptySet(),
|
||||
mode = currentMode.getCurrentMode(),
|
||||
tabs = emptyList(),
|
||||
topSites = emptyList()
|
||||
)
|
||||
|
||||
|
@ -64,38 +63,14 @@ class HomeFragmentStoreTest {
|
|||
fun `Test toggling the mode 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)
|
||||
|
||||
// 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)
|
||||
|
||||
// Change the HomeFragmentStore back to Normal mode.
|
||||
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(Mode.Normal)).join()
|
||||
|
||||
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
|
||||
|
@ -120,18 +95,6 @@ class HomeFragmentStoreTest {
|
|||
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
|
||||
fun `Test changing the expanded collections in HomeFragmentStore`() = runBlocking {
|
||||
val collection: TabCollection = mockk<TabCollection>().apply {
|
||||
|
@ -147,29 +110,25 @@ class HomeFragmentStoreTest {
|
|||
}
|
||||
|
||||
@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.
|
||||
assertEquals(0, homeFragmentStore.state.collections.size)
|
||||
assertEquals(0, homeFragmentStore.state.tabs.size)
|
||||
assertEquals(0, homeFragmentStore.state.topSites.size)
|
||||
assertEquals(Mode.Normal, homeFragmentStore.state.mode)
|
||||
|
||||
val collections: List<TabCollection> = listOf(mockk())
|
||||
val tabs: List<Tab> = listOf(mockk(), mockk())
|
||||
val topSites: List<TopSite> = listOf(mockk(), mockk())
|
||||
|
||||
homeFragmentStore.dispatch(
|
||||
HomeFragmentAction.Change(
|
||||
collections = collections,
|
||||
mode = Mode.Private,
|
||||
tabs = tabs,
|
||||
topSites = topSites
|
||||
)
|
||||
).join()
|
||||
|
||||
assertEquals(1, homeFragmentStore.state.collections.size)
|
||||
assertEquals(Mode.Private, homeFragmentStore.state.mode)
|
||||
assertEquals(2, homeFragmentStore.state.tabs.size)
|
||||
assertEquals(2, homeFragmentStore.state.topSites.size)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package org.mozilla.fenix.home
|
||||
|
||||
import android.view.View
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.feature.tab.collections.Tab
|
||||
|
@ -25,20 +24,6 @@ class SessionControlInteractorTest {
|
|||
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
|
||||
fun onCollectionAddTabTapped() {
|
||||
val collection: TabCollection = mockk(relaxed = true)
|
||||
|
@ -82,18 +67,6 @@ class SessionControlInteractorTest {
|
|||
verify { controller.handleDeleteCollectionTapped(collection) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPauseMediaClicked() {
|
||||
interactor.onPauseMediaClicked()
|
||||
verify { controller.handlePauseMediaClicked() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPlayMediaClicked() {
|
||||
interactor.onPlayMediaClicked()
|
||||
verify { controller.handlePlayMediaClicked() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onPrivateBrowsingLearnMoreClicked() {
|
||||
interactor.onPrivateBrowsingLearnMoreClicked()
|
||||
|
@ -107,26 +80,6 @@ class SessionControlInteractorTest {
|
|||
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
|
||||
fun 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