WebExtensionReducer.kt
/* 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 mozilla.components.browser.state.reducer
import mozilla.components.browser.state.action.WebExtensionAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.WebExtensionState
internal object WebExtensionReducer {
/**
* [WebExtensionAction] Reducer function for modifying a specific [WebExtensionState] in
* both [SessionState.extensionState] or [BrowserState.extensions].
*/
@Suppress("LongMethod")
fun reduce(state: BrowserState, action: WebExtensionAction): BrowserState {
return when (action) {
is WebExtensionAction.InstallWebExtensionAction -> {
val existingExtension = state.extensions[action.extension.id]
if (existingExtension == null) {
state.copy(
extensions = state.extensions + (action.extension.id to action.extension),
)
} else {
state.updateWebExtensionState(action.extension.id) {
// Keep existing browser and page actions in case we received them before the install action
action.extension.copy(browserAction = it.browserAction, pageAction = it.pageAction)
}
}
}
is WebExtensionAction.UninstallWebExtensionAction -> {
state.copy(
extensions = state.extensions - action.extensionId,
tabs = state.tabs.map { it.copy(extensionState = it.extensionState - action.extensionId) },
)
}
is WebExtensionAction.UninstallAllWebExtensionsAction -> {
state.copy(
extensions = emptyMap(),
tabs = state.tabs.map { it.copy(extensionState = emptyMap()) },
)
}
is WebExtensionAction.UpdateWebExtensionEnabledAction -> {
state.updateWebExtensionState(action.extensionId) {
it.copy(enabled = action.enabled)
}
}
is WebExtensionAction.UpdateWebExtensionAllowedInPrivateBrowsingAction -> {
state.updateWebExtensionState(action.extensionId) {
it.copy(allowedInPrivateBrowsing = action.allowed)
}
}
is WebExtensionAction.UpdateBrowserAction -> {
state.updateWebExtensionState(action.extensionId) {
it.copy(browserAction = action.browserAction)
}
}
is WebExtensionAction.UpdatePageAction -> {
state.updateWebExtensionState(action.extensionId) {
it.copy(pageAction = action.pageAction)
}
}
is WebExtensionAction.UpdatePopupSessionAction -> {
state.updateWebExtensionState(action.extensionId) {
it.copy(popupSessionId = action.popupSessionId, popupSession = action.popupSession)
}
}
is WebExtensionAction.UpdateTabBrowserAction -> {
state.updateWebExtensionTabState(action.sessionId, action.extensionId) {
it.copy(browserAction = action.browserAction)
}
}
is WebExtensionAction.UpdateTabPageAction -> {
state.updateWebExtensionTabState(action.sessionId, action.extensionId) {
it.copy(pageAction = action.pageAction)
}
}
is WebExtensionAction.UpdateWebExtensionAction -> {
state.updateWebExtensionState(action.updatedExtension.id) { action.updatedExtension }
}
is WebExtensionAction.UpdateActiveWebExtensionTabAction -> {
state.copy(activeWebExtensionTabId = action.activeWebExtensionTabId)
}
is WebExtensionAction.UpdatePromptRequestWebExtensionAction -> {
state.copy(webExtensionPromptRequest = action.promptRequest)
}
is WebExtensionAction.ConsumePromptRequestWebExtensionAction -> {
state.copy(webExtensionPromptRequest = null)
}
}
}
private fun BrowserState.updateWebExtensionTabState(
tabId: String,
extensionId: String,
update: (WebExtensionState) -> WebExtensionState,
): BrowserState {
return copy(
tabs = tabs.updateTabs(tabId) { current ->
val existingExtension = current.extensionState[extensionId]
val newExtension = extensionId to update(existingExtension ?: WebExtensionState(extensionId))
current.copy(extensionState = current.extensionState + newExtension)
} ?: tabs,
)
}
private fun BrowserState.updateWebExtensionState(
extensionId: String,
update: (WebExtensionState) -> WebExtensionState,
): BrowserState {
val existingExtension = extensions[extensionId]
val newExtension = extensionId to update(existingExtension ?: WebExtensionState(extensionId))
return copy(extensions = extensions + newExtension)
}
}