mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-09 19:10:42 +00:00
Use "undo" implementation from Android Components.
This is not the super fancy version yet - since we still need to restore into SessionManager and haven't fully switched to BrowserStore yet. However AC having knowledge about "undo" and whether it was performed or not, will help us with features like "recently closed tabs". And once we can improve "undo", Fenix will get all the nice things automatically. Requires: https://github.com/mozilla-mobile/android-components/pull/8449
This commit is contained in:
parent
d287e6e9e0
commit
3983c509dc
@ -260,9 +260,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onCloseTab = { closedSession ->
|
onCloseTab = { closedSession ->
|
||||||
val tab = store.state.findTab(closedSession.id)
|
val tab = store.state.findTab(closedSession.id) ?: return@DefaultBrowserToolbarController
|
||||||
?: return@DefaultBrowserToolbarController
|
|
||||||
val isSelected = tab.id == context.components.core.store.state.selectedTabId
|
|
||||||
|
|
||||||
val snackbarMessage = if (tab.content.private) {
|
val snackbarMessage = if (tab.content.private) {
|
||||||
requireContext().getString(R.string.snackbar_private_tab_closed)
|
requireContext().getString(R.string.snackbar_private_tab_closed)
|
||||||
@ -275,11 +273,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
|||||||
snackbarMessage,
|
snackbarMessage,
|
||||||
requireContext().getString(R.string.snackbar_deleted_undo),
|
requireContext().getString(R.string.snackbar_deleted_undo),
|
||||||
{
|
{
|
||||||
sessionManager.add(
|
requireComponents.useCases.tabsUseCases.undo.invoke()
|
||||||
closedSession,
|
|
||||||
isSelected,
|
|
||||||
engineSessionState = tab.engineState.engineSessionState
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
operation = { }
|
operation = { }
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,7 @@ import mozilla.components.browser.session.Session
|
|||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.browser.session.engine.EngineMiddleware
|
import mozilla.components.browser.session.engine.EngineMiddleware
|
||||||
import mozilla.components.browser.session.storage.SessionStorage
|
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.action.RecentlyClosedAction
|
||||||
import mozilla.components.browser.state.state.BrowserState
|
import mozilla.components.browser.state.state.BrowserState
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
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.SupportUtils
|
||||||
import org.mozilla.fenix.settings.advanced.getSelectedLocale
|
import org.mozilla.fenix.settings.advanced.getSelectedLocale
|
||||||
import org.mozilla.fenix.utils.Mockable
|
import org.mozilla.fenix.utils.Mockable
|
||||||
|
import org.mozilla.fenix.utils.getUndoDelay
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,13 +148,18 @@ class Core(private val context: Context, private val crashReporter: CrashReporti
|
|||||||
MediaMiddleware(context, MediaService::class.java),
|
MediaMiddleware(context, MediaService::class.java),
|
||||||
DownloadMiddleware(context, DownloadService::class.java),
|
DownloadMiddleware(context, DownloadService::class.java),
|
||||||
ReaderViewMiddleware(),
|
ReaderViewMiddleware(),
|
||||||
ThumbnailsMiddleware(thumbnailStorage)
|
ThumbnailsMiddleware(thumbnailStorage),
|
||||||
|
UndoMiddleware(::lookupSessionManager, context.getUndoDelay())
|
||||||
) + EngineMiddleware.create(engine, ::findSessionById)
|
) + EngineMiddleware.create(engine, ::findSessionById)
|
||||||
).also {
|
).also {
|
||||||
it.dispatch(RecentlyClosedAction.InitializeRecentlyClosedState)
|
it.dispatch(RecentlyClosedAction.InitializeRecentlyClosedState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun lookupSessionManager(): SessionManager {
|
||||||
|
return sessionManager
|
||||||
|
}
|
||||||
|
|
||||||
private fun findSessionById(tabId: String): Session? {
|
private fun findSessionById(tabId: String): Session? {
|
||||||
return sessionManager.findSessionById(tabId)
|
return sessionManager.findSessionById(tabId)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,6 @@ import org.mozilla.fenix.ext.metrics
|
|||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.resetPoliciesAfter
|
import org.mozilla.fenix.ext.resetPoliciesAfter
|
||||||
import org.mozilla.fenix.ext.sessionsOfType
|
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.home.sessioncontrol.DefaultSessionControlController
|
import org.mozilla.fenix.home.sessioncontrol.DefaultSessionControlController
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
||||||
@ -469,17 +468,10 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAllTabsAndShowSnackbar(sessionCode: String) {
|
private fun removeAllTabsAndShowSnackbar(sessionCode: String) {
|
||||||
val tabs = sessionManager.sessionsOfType(private = sessionCode == ALL_PRIVATE_TABS).toList()
|
if (sessionCode == ALL_PRIVATE_TABS) {
|
||||||
val selectedIndex = sessionManager
|
sessionManager.removePrivateSessions()
|
||||||
.selectedSession?.let { sessionManager.sessions.indexOf(it) }
|
} else {
|
||||||
?: SessionManager.NO_SELECTION
|
sessionManager.removeNormalSessions()
|
||||||
|
|
||||||
val snapshot = tabs
|
|
||||||
.map(sessionManager::createSessionSnapshot)
|
|
||||||
.let { SessionManager.Snapshot(it, selectedIndex) }
|
|
||||||
|
|
||||||
tabs.forEach {
|
|
||||||
requireComponents.useCases.tabsUseCases.removeTab(it)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val snackbarMessage = if (sessionCode == ALL_PRIVATE_TABS) {
|
val snackbarMessage = if (sessionCode == ALL_PRIVATE_TABS) {
|
||||||
@ -493,7 +485,7 @@ class HomeFragment : Fragment() {
|
|||||||
snackbarMessage,
|
snackbarMessage,
|
||||||
requireContext().getString(R.string.snackbar_deleted_undo),
|
requireContext().getString(R.string.snackbar_deleted_undo),
|
||||||
{
|
{
|
||||||
sessionManager.restore(snapshot)
|
requireComponents.useCases.tabsUseCases.undo.invoke()
|
||||||
},
|
},
|
||||||
operation = { },
|
operation = { },
|
||||||
anchorView = snackbarAnchorView
|
anchorView = snackbarAnchorView
|
||||||
@ -501,15 +493,11 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun removeTabAndShowSnackbar(sessionId: String) {
|
private fun removeTabAndShowSnackbar(sessionId: String) {
|
||||||
sessionManager.findSessionById(sessionId)?.let { session ->
|
val tab = store.state.findTab(sessionId) ?: return
|
||||||
val snapshot = sessionManager.createSessionSnapshot(session)
|
|
||||||
val state = store.state.findTab(sessionId)?.engineState?.engineSessionState
|
|
||||||
val isSelected =
|
|
||||||
session.id == requireComponents.core.store.state.selectedTabId ?: false
|
|
||||||
|
|
||||||
requireComponents.useCases.tabsUseCases.removeTab(sessionId)
|
requireComponents.useCases.tabsUseCases.removeTab(sessionId)
|
||||||
|
|
||||||
val snackbarMessage = if (snapshot.session.private) {
|
val snackbarMessage = if (tab.content.private) {
|
||||||
requireContext().getString(R.string.snackbar_private_tab_closed)
|
requireContext().getString(R.string.snackbar_private_tab_closed)
|
||||||
} else {
|
} else {
|
||||||
requireContext().getString(R.string.snackbar_tab_closed)
|
requireContext().getString(R.string.snackbar_tab_closed)
|
||||||
@ -520,11 +508,7 @@ class HomeFragment : Fragment() {
|
|||||||
snackbarMessage,
|
snackbarMessage,
|
||||||
requireContext().getString(R.string.snackbar_deleted_undo),
|
requireContext().getString(R.string.snackbar_deleted_undo),
|
||||||
{
|
{
|
||||||
sessionManager.add(
|
requireComponents.useCases.tabsUseCases.undo.invoke()
|
||||||
snapshot.session,
|
|
||||||
isSelected,
|
|
||||||
engineSessionState = state
|
|
||||||
)
|
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
HomeFragmentDirections.actionGlobalBrowser(null)
|
HomeFragmentDirections.actionGlobalBrowser(null)
|
||||||
)
|
)
|
||||||
@ -533,7 +517,6 @@ class HomeFragment : Fragment() {
|
|||||||
anchorView = snackbarAnchorView
|
anchorView = snackbarAnchorView
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
@ -260,10 +260,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
|
|||||||
|
|
||||||
private fun showUndoSnackbarForTab(sessionId: String) {
|
private fun showUndoSnackbarForTab(sessionId: String) {
|
||||||
val store = requireComponents.core.store
|
val store = requireComponents.core.store
|
||||||
val sessionManager = requireComponents.core.sessionManager
|
|
||||||
|
|
||||||
val tab = requireComponents.core.store.state.findTab(sessionId) ?: return
|
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
|
// Check if this is the last tab of this session type
|
||||||
val isLastOpenTab =
|
val isLastOpenTab =
|
||||||
@ -273,8 +270,6 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val isSelected = sessionId == requireComponents.core.store.state.selectedTabId ?: false
|
|
||||||
|
|
||||||
val snackbarMessage = if (tab.content.private) {
|
val snackbarMessage = if (tab.content.private) {
|
||||||
getString(R.string.snackbar_private_tab_closed)
|
getString(R.string.snackbar_private_tab_closed)
|
||||||
} else {
|
} else {
|
||||||
@ -286,12 +281,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
|
|||||||
snackbarMessage,
|
snackbarMessage,
|
||||||
getString(R.string.snackbar_deleted_undo),
|
getString(R.string.snackbar_deleted_undo),
|
||||||
{
|
{
|
||||||
sessionManager.add(
|
requireComponents.useCases.tabsUseCases.undo.invoke()
|
||||||
session,
|
_tabTrayView?.scrollToTab(tab.id)
|
||||||
isSelected,
|
|
||||||
engineSessionState = tab.engineState.engineSessionState
|
|
||||||
)
|
|
||||||
_tabTrayView?.scrollToTab(session.id)
|
|
||||||
},
|
},
|
||||||
operation = { },
|
operation = { },
|
||||||
elevation = ELEVATION,
|
elevation = ELEVATION,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package org.mozilla.fenix.utils
|
package org.mozilla.fenix.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.ContentFrameLayout
|
import androidx.appcompat.widget.ContentFrameLayout
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
@ -19,6 +20,18 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
internal const val UNDO_DELAY = 3000L
|
internal const val UNDO_DELAY = 3000L
|
||||||
internal const val ACCESSIBLE_UNDO_DELAY = 15000L
|
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.
|
* Runs [operation] after giving user time (see [UNDO_DELAY]) to cancel it.
|
||||||
* In case of cancellation, [onCancel] is executed.
|
* 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
|
// Wait a bit, and if user didn't request cancellation, proceed with
|
||||||
// requested operation and hide the snackbar.
|
// requested operation and hide the snackbar.
|
||||||
launch {
|
launch {
|
||||||
val lengthToDelay = if (view.context.settings().accessibilityServicesEnabled) {
|
delay(view.context.getUndoDelay())
|
||||||
ACCESSIBLE_UNDO_DELAY
|
|
||||||
} else {
|
|
||||||
UNDO_DELAY
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(lengthToDelay)
|
|
||||||
|
|
||||||
if (!requestedUndo.get()) {
|
if (!requestedUndo.get()) {
|
||||||
snackbar.dismiss()
|
snackbar.dismiss()
|
||||||
|
Loading…
Reference in New Issue
Block a user