diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index ddc61a1e6c..591f28bb23 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -52,6 +52,7 @@ import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.OAuthAccount import mozilla.components.feature.tab.collections.TabCollection +import mozilla.components.feature.top.sites.TopSite import mozilla.components.feature.top.sites.TopSitesConfig import mozilla.components.feature.top.sites.TopSitesFeature import mozilla.components.feature.top.sites.TopSitesFrecencyConfig @@ -351,6 +352,7 @@ class HomeFragment : Fragment() { viewLifecycleScope = viewLifecycleOwner.lifecycleScope, registerCollectionStorageObserver = ::registerCollectionStorageObserver, removeCollectionWithUndo = ::removeCollectionWithUndo, + showUndoSnackbarForTopSite = ::showUndoSnackbarForTopSite, showTabTray = ::openTabsTray, ), recentTabController = DefaultRecentTabsController( @@ -461,6 +463,24 @@ class HomeFragment : Fragment() { ) } + @VisibleForTesting + internal fun showUndoSnackbarForTopSite(topSite: TopSite) { + lifecycleScope.allowUndo( + view = requireView(), + message = getString(R.string.snackbar_top_site_removed), + undoActionTitle = getString(R.string.snackbar_deleted_undo), + onCancel = { + requireComponents.useCases.topSitesUseCase.addPinnedSites( + topSite.title.toString(), + topSite.url, + ) + }, + operation = { }, + elevation = TOAST_ELEVATION, + paddedForBottomToolbar = true, + ) + } + /** * The [SessionControlView] is forced to update with our current state when we call * [HomeFragment.onCreateView] in order to be able to draw everything at once with the current diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index f2df81e519..0cfecbeca6 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -193,6 +193,7 @@ class DefaultSessionControlController( private val viewLifecycleScope: CoroutineScope, private val registerCollectionStorageObserver: () -> Unit, private val removeCollectionWithUndo: (tabCollection: TabCollection) -> Unit, + private val showUndoSnackbarForTopSite: (topSite: TopSite) -> Unit, private val showTabTray: () -> Unit, ) : SessionControlController { @@ -332,6 +333,8 @@ class DefaultSessionControlController( removeTopSites(topSite) } } + + showUndoSnackbarForTopSite(topSite) } override fun handleRenameCollectionTapped(collection: TabCollection) { diff --git a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt index 1d9e20c1ec..cfd540a199 100644 --- a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt @@ -867,6 +867,28 @@ class DefaultSessionControlControllerTest { assertNull(TopSites.remove.testGetValue()!!.single().extra) } + @Test + fun `WHEN top site is removed THEN the undo snackbar is called`() { + val mozillaTopSite = TopSite.Default( + id = 1L, + title = "Mozilla", + url = "https://mozilla.org", + null, + ) + var undoSnackbarCalled = false + var undoSnackbarShownFor = "TopSiteName" + + createController( + showUndoSnackbarForTopSite = { topSite -> + undoSnackbarCalled = true + undoSnackbarShownFor = topSite.title.toString() + }, + ).handleRemoveTopSiteClicked(mozillaTopSite) + + assertEquals(true, undoSnackbarCalled) + assertEquals("Mozilla", undoSnackbarShownFor) + } + @Test fun `GIVEN exactly the required amount of downloaded thumbnails with no errors WHEN handling wallpaper dialog THEN dialog is shown`() { val wallpaperState = WallpaperState.default.copy( @@ -1142,6 +1164,7 @@ class DefaultSessionControlControllerTest { registerCollectionStorageObserver: () -> Unit = { }, showTabTray: () -> Unit = { }, removeCollectionWithUndo: (tabCollection: TabCollection) -> Unit = { }, + showUndoSnackbarForTopSite: (topSite: TopSite) -> Unit = { }, ): DefaultSessionControlController { return DefaultSessionControlController( activity = activity, @@ -1159,6 +1182,7 @@ class DefaultSessionControlControllerTest { viewLifecycleScope = scope, registerCollectionStorageObserver = registerCollectionStorageObserver, removeCollectionWithUndo = removeCollectionWithUndo, + showUndoSnackbarForTopSite = showUndoSnackbarForTopSite, showTabTray = showTabTray, ) } diff --git a/app/src/test/java/org/mozilla/fenix/home/HomeFragmentTest.kt b/app/src/test/java/org/mozilla/fenix/home/HomeFragmentTest.kt index 3e1c3fcb78..d7f659b26d 100644 --- a/app/src/test/java/org/mozilla/fenix/home/HomeFragmentTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/HomeFragmentTest.kt @@ -5,10 +5,19 @@ package org.mozilla.fenix.home import android.content.Context +import android.view.ViewGroup +import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import io.mockk.Runs import io.mockk.every +import io.mockk.just import io.mockk.mockk +import io.mockk.mockkStatic import io.mockk.spyk +import io.mockk.unmockkStatic import io.mockk.verify +import kotlinx.coroutines.CoroutineScope import mozilla.components.browser.state.search.SearchEngine import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.SearchState @@ -22,12 +31,15 @@ import org.junit.Before import org.junit.Test import org.mozilla.fenix.FenixApplication import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.R import org.mozilla.fenix.components.Core import org.mozilla.fenix.ext.application import org.mozilla.fenix.ext.components import org.mozilla.fenix.home.HomeFragment.Companion.AMAZON_SPONSORED_TITLE import org.mozilla.fenix.home.HomeFragment.Companion.EBAY_SPONSORED_TITLE +import org.mozilla.fenix.home.HomeFragment.Companion.TOAST_ELEVATION import org.mozilla.fenix.utils.Settings +import org.mozilla.fenix.utils.allowUndo class HomeFragmentTest { @@ -127,4 +139,54 @@ class HomeFragmentTest { assertFalse(homeFragment.shouldEnableWallpaper()) } + + @Test + fun `WHEN a pinned top is removed THEN show the undo snackbar`() { + try { + val topSite = TopSite.Default( + id = 1L, + title = "Mozilla", + url = "https://mozilla.org", + null, + ) + mockkStatic("org.mozilla.fenix.utils.UndoKt") + mockkStatic("androidx.lifecycle.LifecycleOwnerKt") + val view: ViewGroup = mockk(relaxed = true) + val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true) + every { any().lifecycleScope } returns lifecycleScope + every { homeFragment.getString(R.string.snackbar_top_site_removed) } returns "Mocked Removed Top Site" + every { homeFragment.getString(R.string.snackbar_deleted_undo) } returns "Mocked Undo Removal" + every { + any().allowUndo( + any(), + any(), + any(), + any(), + any(), + any(), + any(), + any(), + ) + } just Runs + every { homeFragment.requireView() } returns view + + homeFragment.showUndoSnackbarForTopSite(topSite) + + verify { + lifecycleScope.allowUndo( + view, + "Mocked Removed Top Site", + "Mocked Undo Removal", + any(), + any(), + any(), + TOAST_ELEVATION, + true, + ) + } + } finally { + unmockkStatic("org.mozilla.fenix.utils.UndoKt") + unmockkStatic("androidx.lifecycle.LifecycleOwnerKt") + } + } }