diff --git a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 72c2cd9d5..352fcc522 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -260,9 +260,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session ) }, onCloseTab = { closedSession -> - val tab = store.state.findTab(closedSession.id) - ?: return@DefaultBrowserToolbarController - val isSelected = tab.id == context.components.core.store.state.selectedTabId + val tab = store.state.findTab(closedSession.id) ?: return@DefaultBrowserToolbarController val snackbarMessage = if (tab.content.private) { requireContext().getString(R.string.snackbar_private_tab_closed) @@ -275,11 +273,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session snackbarMessage, requireContext().getString(R.string.snackbar_deleted_undo), { - sessionManager.add( - closedSession, - isSelected, - engineSessionState = tab.engineState.engineSessionState - ) + requireComponents.useCases.tabsUseCases.undo.invoke() }, operation = { } ) diff --git a/app/src/main/java/org/mozilla/fenix/components/Core.kt b/app/src/main/java/org/mozilla/fenix/components/Core.kt index fbec09a5d..a2ae6f888 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Core.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Core.kt @@ -20,6 +20,7 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.engine.EngineMiddleware import mozilla.components.browser.session.storage.SessionStorage +import mozilla.components.browser.session.undo.UndoMiddleware import mozilla.components.browser.state.action.RecentlyClosedAction import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.store.BrowserStore @@ -69,6 +70,7 @@ import org.mozilla.fenix.search.telemetry.incontent.InContentTelemetry import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.advanced.getSelectedLocale import org.mozilla.fenix.utils.Mockable +import org.mozilla.fenix.utils.getUndoDelay import java.util.concurrent.TimeUnit /** @@ -146,13 +148,18 @@ class Core(private val context: Context, private val crashReporter: CrashReporti MediaMiddleware(context, MediaService::class.java), DownloadMiddleware(context, DownloadService::class.java), ReaderViewMiddleware(), - ThumbnailsMiddleware(thumbnailStorage) + ThumbnailsMiddleware(thumbnailStorage), + UndoMiddleware(::lookupSessionManager, context.getUndoDelay()) ) + EngineMiddleware.create(engine, ::findSessionById) ).also { it.dispatch(RecentlyClosedAction.InitializeRecentlyClosedState) } } + private fun lookupSessionManager(): SessionManager { + return sessionManager + } + private fun findSessionById(tabId: String): Session? { return sessionManager.findSessionById(tabId) } 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 6df4a4131..707c584ee 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -92,7 +92,6 @@ import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.resetPoliciesAfter -import org.mozilla.fenix.ext.sessionsOfType import org.mozilla.fenix.ext.settings import org.mozilla.fenix.home.sessioncontrol.DefaultSessionControlController import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor @@ -469,17 +468,10 @@ class HomeFragment : Fragment() { } private fun removeAllTabsAndShowSnackbar(sessionCode: String) { - val tabs = sessionManager.sessionsOfType(private = sessionCode == ALL_PRIVATE_TABS).toList() - val selectedIndex = sessionManager - .selectedSession?.let { sessionManager.sessions.indexOf(it) } - ?: SessionManager.NO_SELECTION - - val snapshot = tabs - .map(sessionManager::createSessionSnapshot) - .let { SessionManager.Snapshot(it, selectedIndex) } - - tabs.forEach { - requireComponents.useCases.tabsUseCases.removeTab(it) + if (sessionCode == ALL_PRIVATE_TABS) { + sessionManager.removePrivateSessions() + } else { + sessionManager.removeNormalSessions() } val snackbarMessage = if (sessionCode == ALL_PRIVATE_TABS) { @@ -493,7 +485,7 @@ class HomeFragment : Fragment() { snackbarMessage, requireContext().getString(R.string.snackbar_deleted_undo), { - sessionManager.restore(snapshot) + requireComponents.useCases.tabsUseCases.undo.invoke() }, operation = { }, anchorView = snackbarAnchorView @@ -501,38 +493,29 @@ class HomeFragment : Fragment() { } private fun removeTabAndShowSnackbar(sessionId: String) { - sessionManager.findSessionById(sessionId)?.let { session -> - val snapshot = sessionManager.createSessionSnapshot(session) - val state = store.state.findTab(sessionId)?.engineState?.engineSessionState - val isSelected = - session.id == requireComponents.core.store.state.selectedTabId ?: false + val tab = store.state.findTab(sessionId) ?: return - requireComponents.useCases.tabsUseCases.removeTab(sessionId) - - val snackbarMessage = if (snapshot.session.private) { - requireContext().getString(R.string.snackbar_private_tab_closed) - } else { - requireContext().getString(R.string.snackbar_tab_closed) - } + requireComponents.useCases.tabsUseCases.removeTab(sessionId) - viewLifecycleOwner.lifecycleScope.allowUndo( - requireView(), - snackbarMessage, - requireContext().getString(R.string.snackbar_deleted_undo), - { - sessionManager.add( - snapshot.session, - isSelected, - engineSessionState = state - ) - findNavController().navigate( - HomeFragmentDirections.actionGlobalBrowser(null) - ) - }, - operation = { }, - anchorView = snackbarAnchorView - ) + val snackbarMessage = if (tab.content.private) { + requireContext().getString(R.string.snackbar_private_tab_closed) + } else { + requireContext().getString(R.string.snackbar_tab_closed) } + + viewLifecycleOwner.lifecycleScope.allowUndo( + requireView(), + snackbarMessage, + requireContext().getString(R.string.snackbar_deleted_undo), + { + requireComponents.useCases.tabsUseCases.undo.invoke() + findNavController().navigate( + HomeFragmentDirections.actionGlobalBrowser(null) + ) + }, + operation = { }, + anchorView = snackbarAnchorView + ) } override fun onDestroyView() { diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt index f03bd170c..858be4e76 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt @@ -260,10 +260,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler private fun showUndoSnackbarForTab(sessionId: String) { val store = requireComponents.core.store - val sessionManager = requireComponents.core.sessionManager - val tab = requireComponents.core.store.state.findTab(sessionId) ?: return - val session = sessionManager.findSessionById(sessionId) ?: return // Check if this is the last tab of this session type val isLastOpenTab = @@ -273,8 +270,6 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler return } - val isSelected = sessionId == requireComponents.core.store.state.selectedTabId ?: false - val snackbarMessage = if (tab.content.private) { getString(R.string.snackbar_private_tab_closed) } else { @@ -286,12 +281,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler snackbarMessage, getString(R.string.snackbar_deleted_undo), { - sessionManager.add( - session, - isSelected, - engineSessionState = tab.engineState.engineSessionState - ) - _tabTrayView?.scrollToTab(session.id) + requireComponents.useCases.tabsUseCases.undo.invoke() + _tabTrayView?.scrollToTab(tab.id) }, operation = { }, elevation = ELEVATION, diff --git a/app/src/main/java/org/mozilla/fenix/utils/Undo.kt b/app/src/main/java/org/mozilla/fenix/utils/Undo.kt index 26dbf59ee..6dd272f5a 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Undo.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Undo.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.utils +import android.content.Context import android.view.View import androidx.appcompat.widget.ContentFrameLayout import androidx.core.view.updatePadding @@ -19,6 +20,18 @@ import java.util.concurrent.atomic.AtomicBoolean internal const val UNDO_DELAY = 3000L internal const val ACCESSIBLE_UNDO_DELAY = 15000L +/** + * Get the recommended time an "undo" action should be available until it can automatically be + * dismissed. The delay may be different based on the accessibility settings of the device. + */ +fun Context.getUndoDelay(): Long { + return if (settings().accessibilityServicesEnabled) { + ACCESSIBLE_UNDO_DELAY + } else { + UNDO_DELAY + } +} + /** * Runs [operation] after giving user time (see [UNDO_DELAY]) to cancel it. * In case of cancellation, [onCancel] is executed. @@ -92,13 +105,7 @@ fun CoroutineScope.allowUndo( // Wait a bit, and if user didn't request cancellation, proceed with // requested operation and hide the snackbar. launch { - val lengthToDelay = if (view.context.settings().accessibilityServicesEnabled) { - ACCESSIBLE_UNDO_DELAY - } else { - UNDO_DELAY - } - - delay(lengthToDelay) + delay(view.context.getUndoDelay()) if (!requestedUndo.get()) { snackbar.dismiss()