Loading components/browser/state/src/main/java/mozilla/components/browser/state/action/BrowserAction.kt +6 −0 Original line number Diff line number Diff line Loading @@ -270,6 +270,12 @@ sealed class WebExtensionAction : BrowserAction() { */ data class InstallWebExtensionAction(val extension: WebExtensionState) : WebExtensionAction() /** * Updates the [WebExtensionState.enabled] flag. */ data class UpdateWebExtensionEnabledAction(val extensionId: String, val enabled: Boolean) : WebExtensionAction() /** * Updates a browser action of a given [extensionId]. */ Loading components/browser/state/src/main/java/mozilla/components/browser/state/reducer/WebExtensionReducer.kt +34 −46 Original line number Diff line number Diff line Loading @@ -7,7 +7,6 @@ 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.TabSessionState import mozilla.components.browser.state.state.WebExtensionState internal object WebExtensionReducer { Loading @@ -27,71 +26,60 @@ internal object WebExtensionReducer { state } } is WebExtensionAction.UpdateWebExtensionEnabledAction -> { state.updateWebExtensionState(action.extensionId) { it.copy(enabled = action.enabled) } } is WebExtensionAction.UpdateBrowserAction -> { val newExtension = action.extensionId to WebExtensionState( id = action.extensionId, browserAction = action.browserAction ) val updatedExtensions = state.extensions - action.extensionId state.copy( extensions = updatedExtensions + newExtension ) state.updateWebExtensionState(action.extensionId) { it.copy(browserAction = action.browserAction) } } is WebExtensionAction.UpdateBrowserActionPopupSession -> { val existingExtension = state.extensions[action.extensionId] if (existingExtension == null) { state } else { val newExtension = action.extensionId to existingExtension.copy( browserActionPopupSession = action.popupSessionId ) val updatedExtensions = state.extensions - action.extensionId state.copy( extensions = updatedExtensions + newExtension ) state.updateWebExtensionState(action.extensionId) { it.copy(browserActionPopupSession = action.popupSessionId) } } is WebExtensionAction.UpdateTabBrowserAction -> { state.updateTabState(action.sessionId) { tab -> val existingExtension = tab.extensionState[action.extensionId] val newExtension = action.extensionId to WebExtensionState( id = action.extensionId, browserAction = action.browserAction ) val updatedExtensions = if (existingExtension == null) { tab.extensionState + newExtension } else { val newExtensions = tab.extensionState - action.extensionId newExtensions + newExtension } tab.copy( extensionState = updatedExtensions ) state.updateWebExtensionTabState(action.sessionId, action.extensionId) { it.copy(browserAction = action.browserAction) } } } } private fun BrowserState.updateTabState( private fun BrowserState.updateWebExtensionTabState( tabId: String, update: (TabSessionState) -> TabSessionState extensionId: String, update: (WebExtensionState) -> WebExtensionState ): BrowserState { return copy( tabs = tabs.map { current -> if (current.id == tabId) { update(current) val existingExtension = current.extensionState[extensionId] val newExtension = extensionId to update(existingExtension ?: WebExtensionState(extensionId)) val updatedExtensions = if (existingExtension == null) { current.extensionState + newExtension } else { val newExtensions = current.extensionState - extensionId newExtensions + newExtension } current.copy(extensionState = updatedExtensions) } else { current } } ) } private fun BrowserState.updateWebExtensionState( extensionId: String, update: (WebExtensionState) -> WebExtensionState ): BrowserState { val existingExtension = extensions[extensionId] val newExtension = extensionId to update(existingExtension ?: WebExtensionState(extensionId)) val updatedExtensions = extensions - extensionId return copy(extensions = updatedExtensions + newExtension) } } components/browser/state/src/main/java/mozilla/components/browser/state/state/WebExtensionState.kt +2 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ typealias WebExtensionBrowserAction = mozilla.components.concept.engine.webexten * @property id The unique identifier for this web extension. * @property url The url pointing to a resources path for locating the extension * within the APK file e.g. resource://android/assets/extensions/my_web_ext. * @property enabled Whether or not this web extension is enabled, defaults to true. * @property browserAction A list browser action that this web extension has. * @property browserActionPopupSession The ID of the session displaying * the browser action popup. Loading @@ -19,6 +20,7 @@ typealias WebExtensionBrowserAction = mozilla.components.concept.engine.webexten data class WebExtensionState( val id: String, val url: String? = null, val enabled: Boolean = true, val browserAction: WebExtensionBrowserAction? = null, val browserActionPopupSession: String? = null ) components/browser/state/src/test/java/mozilla/components/browser/state/action/WebExtensionActionTest.kt +22 −7 Original line number Diff line number Diff line Loading @@ -43,20 +43,19 @@ class WebExtensionActionTest { fun `UpdateGlobalBrowserAction - Updates a browser action of an existing WebExtensionState on the BrowserState`() { val store = BrowserStore() val mockedBrowserAction = mock<WebExtensionBrowserAction>() val mockedBrowserAction2 = mock<WebExtensionBrowserAction>() assertTrue(store.state.extensions.isEmpty()) store.dispatch(WebExtensionAction.UpdateBrowserAction("id", mockedBrowserAction)).joinBlocking() assertEquals(mockedBrowserAction, store.state.extensions.values.first().browserAction) val extension = WebExtensionState("id", "url") store.dispatch(WebExtensionAction.InstallWebExtensionAction(extension)).joinBlocking() assertFalse(store.state.extensions.isEmpty()) assertEquals(extension, store.state.extensions.values.first()) store.dispatch(WebExtensionAction.UpdateBrowserAction("id", mockedBrowserAction)) .joinBlocking() assertEquals(mockedBrowserAction, store.state.extensions.values.first().browserAction) store.dispatch(WebExtensionAction.UpdateBrowserAction("id", mockedBrowserAction2)).joinBlocking() assertEquals(mockedBrowserAction2, store.state.extensions.values.first().browserAction) } @Test Loading Loading @@ -97,6 +96,7 @@ class WebExtensionActionTest { "extensionId" to WebExtensionState( "extensionId", "url", true, mockedBrowserAction1 ) ) Loading Loading @@ -133,4 +133,19 @@ class WebExtensionActionTest { store.dispatch(WebExtensionAction.UpdateBrowserActionPopupSession(extension.id, "popupId")).joinBlocking() assertEquals("popupId", store.state.extensions[extension.id]?.browserActionPopupSession) } @Test fun `UpdateWebExtensionEnabledAction - Updates enabled state of an existing web extension`() { val store = BrowserStore() val extension = WebExtensionState("id", "url") store.dispatch(WebExtensionAction.InstallWebExtensionAction(extension)).joinBlocking() assertTrue(store.state.extensions[extension.id]?.enabled!!) store.dispatch(WebExtensionAction.UpdateWebExtensionEnabledAction(extension.id, false)).joinBlocking() assertFalse(store.state.extensions[extension.id]?.enabled!!) store.dispatch(WebExtensionAction.UpdateWebExtensionEnabledAction(extension.id, true)).joinBlocking() assertTrue(store.state.extensions[extension.id]?.enabled!!) } } components/feature/toolbar/src/test/java/mozilla/components/feature/toolbar/WebExtensionToolbarFeatureTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -46,10 +46,10 @@ class WebExtensionToolbarFeatureTest { WebExtensionBrowserAction("overridden_title", false, mock(), "", 0, 0) {} val toolbar: Toolbar = mock() val extensions: Map<String, WebExtensionState> = mapOf( "id" to WebExtensionState("id", "url", defaultBrowserAction) "id" to WebExtensionState("id", "url", true, defaultBrowserAction) ) val overriddenExtensions: Map<String, WebExtensionState> = mapOf( "id" to WebExtensionState("id", "url", overriddenBrowserAction) "id" to WebExtensionState("id", "url", true, overriddenBrowserAction) ) val store = spy( BrowserStore( Loading Loading
components/browser/state/src/main/java/mozilla/components/browser/state/action/BrowserAction.kt +6 −0 Original line number Diff line number Diff line Loading @@ -270,6 +270,12 @@ sealed class WebExtensionAction : BrowserAction() { */ data class InstallWebExtensionAction(val extension: WebExtensionState) : WebExtensionAction() /** * Updates the [WebExtensionState.enabled] flag. */ data class UpdateWebExtensionEnabledAction(val extensionId: String, val enabled: Boolean) : WebExtensionAction() /** * Updates a browser action of a given [extensionId]. */ Loading
components/browser/state/src/main/java/mozilla/components/browser/state/reducer/WebExtensionReducer.kt +34 −46 Original line number Diff line number Diff line Loading @@ -7,7 +7,6 @@ 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.TabSessionState import mozilla.components.browser.state.state.WebExtensionState internal object WebExtensionReducer { Loading @@ -27,71 +26,60 @@ internal object WebExtensionReducer { state } } is WebExtensionAction.UpdateWebExtensionEnabledAction -> { state.updateWebExtensionState(action.extensionId) { it.copy(enabled = action.enabled) } } is WebExtensionAction.UpdateBrowserAction -> { val newExtension = action.extensionId to WebExtensionState( id = action.extensionId, browserAction = action.browserAction ) val updatedExtensions = state.extensions - action.extensionId state.copy( extensions = updatedExtensions + newExtension ) state.updateWebExtensionState(action.extensionId) { it.copy(browserAction = action.browserAction) } } is WebExtensionAction.UpdateBrowserActionPopupSession -> { val existingExtension = state.extensions[action.extensionId] if (existingExtension == null) { state } else { val newExtension = action.extensionId to existingExtension.copy( browserActionPopupSession = action.popupSessionId ) val updatedExtensions = state.extensions - action.extensionId state.copy( extensions = updatedExtensions + newExtension ) state.updateWebExtensionState(action.extensionId) { it.copy(browserActionPopupSession = action.popupSessionId) } } is WebExtensionAction.UpdateTabBrowserAction -> { state.updateTabState(action.sessionId) { tab -> val existingExtension = tab.extensionState[action.extensionId] val newExtension = action.extensionId to WebExtensionState( id = action.extensionId, browserAction = action.browserAction ) val updatedExtensions = if (existingExtension == null) { tab.extensionState + newExtension } else { val newExtensions = tab.extensionState - action.extensionId newExtensions + newExtension } tab.copy( extensionState = updatedExtensions ) state.updateWebExtensionTabState(action.sessionId, action.extensionId) { it.copy(browserAction = action.browserAction) } } } } private fun BrowserState.updateTabState( private fun BrowserState.updateWebExtensionTabState( tabId: String, update: (TabSessionState) -> TabSessionState extensionId: String, update: (WebExtensionState) -> WebExtensionState ): BrowserState { return copy( tabs = tabs.map { current -> if (current.id == tabId) { update(current) val existingExtension = current.extensionState[extensionId] val newExtension = extensionId to update(existingExtension ?: WebExtensionState(extensionId)) val updatedExtensions = if (existingExtension == null) { current.extensionState + newExtension } else { val newExtensions = current.extensionState - extensionId newExtensions + newExtension } current.copy(extensionState = updatedExtensions) } else { current } } ) } private fun BrowserState.updateWebExtensionState( extensionId: String, update: (WebExtensionState) -> WebExtensionState ): BrowserState { val existingExtension = extensions[extensionId] val newExtension = extensionId to update(existingExtension ?: WebExtensionState(extensionId)) val updatedExtensions = extensions - extensionId return copy(extensions = updatedExtensions + newExtension) } }
components/browser/state/src/main/java/mozilla/components/browser/state/state/WebExtensionState.kt +2 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ typealias WebExtensionBrowserAction = mozilla.components.concept.engine.webexten * @property id The unique identifier for this web extension. * @property url The url pointing to a resources path for locating the extension * within the APK file e.g. resource://android/assets/extensions/my_web_ext. * @property enabled Whether or not this web extension is enabled, defaults to true. * @property browserAction A list browser action that this web extension has. * @property browserActionPopupSession The ID of the session displaying * the browser action popup. Loading @@ -19,6 +20,7 @@ typealias WebExtensionBrowserAction = mozilla.components.concept.engine.webexten data class WebExtensionState( val id: String, val url: String? = null, val enabled: Boolean = true, val browserAction: WebExtensionBrowserAction? = null, val browserActionPopupSession: String? = null )
components/browser/state/src/test/java/mozilla/components/browser/state/action/WebExtensionActionTest.kt +22 −7 Original line number Diff line number Diff line Loading @@ -43,20 +43,19 @@ class WebExtensionActionTest { fun `UpdateGlobalBrowserAction - Updates a browser action of an existing WebExtensionState on the BrowserState`() { val store = BrowserStore() val mockedBrowserAction = mock<WebExtensionBrowserAction>() val mockedBrowserAction2 = mock<WebExtensionBrowserAction>() assertTrue(store.state.extensions.isEmpty()) store.dispatch(WebExtensionAction.UpdateBrowserAction("id", mockedBrowserAction)).joinBlocking() assertEquals(mockedBrowserAction, store.state.extensions.values.first().browserAction) val extension = WebExtensionState("id", "url") store.dispatch(WebExtensionAction.InstallWebExtensionAction(extension)).joinBlocking() assertFalse(store.state.extensions.isEmpty()) assertEquals(extension, store.state.extensions.values.first()) store.dispatch(WebExtensionAction.UpdateBrowserAction("id", mockedBrowserAction)) .joinBlocking() assertEquals(mockedBrowserAction, store.state.extensions.values.first().browserAction) store.dispatch(WebExtensionAction.UpdateBrowserAction("id", mockedBrowserAction2)).joinBlocking() assertEquals(mockedBrowserAction2, store.state.extensions.values.first().browserAction) } @Test Loading Loading @@ -97,6 +96,7 @@ class WebExtensionActionTest { "extensionId" to WebExtensionState( "extensionId", "url", true, mockedBrowserAction1 ) ) Loading Loading @@ -133,4 +133,19 @@ class WebExtensionActionTest { store.dispatch(WebExtensionAction.UpdateBrowserActionPopupSession(extension.id, "popupId")).joinBlocking() assertEquals("popupId", store.state.extensions[extension.id]?.browserActionPopupSession) } @Test fun `UpdateWebExtensionEnabledAction - Updates enabled state of an existing web extension`() { val store = BrowserStore() val extension = WebExtensionState("id", "url") store.dispatch(WebExtensionAction.InstallWebExtensionAction(extension)).joinBlocking() assertTrue(store.state.extensions[extension.id]?.enabled!!) store.dispatch(WebExtensionAction.UpdateWebExtensionEnabledAction(extension.id, false)).joinBlocking() assertFalse(store.state.extensions[extension.id]?.enabled!!) store.dispatch(WebExtensionAction.UpdateWebExtensionEnabledAction(extension.id, true)).joinBlocking() assertTrue(store.state.extensions[extension.id]?.enabled!!) } }
components/feature/toolbar/src/test/java/mozilla/components/feature/toolbar/WebExtensionToolbarFeatureTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -46,10 +46,10 @@ class WebExtensionToolbarFeatureTest { WebExtensionBrowserAction("overridden_title", false, mock(), "", 0, 0) {} val toolbar: Toolbar = mock() val extensions: Map<String, WebExtensionState> = mapOf( "id" to WebExtensionState("id", "url", defaultBrowserAction) "id" to WebExtensionState("id", "url", true, defaultBrowserAction) ) val overriddenExtensions: Map<String, WebExtensionState> = mapOf( "id" to WebExtensionState("id", "url", overriddenBrowserAction) "id" to WebExtensionState("id", "url", true, overriddenBrowserAction) ) val store = spy( BrowserStore( Loading