Commit 79d58726 authored by Christian Sadilek's avatar Christian Sadilek Committed by Sebastian Kaspari
Browse files

Closes #3559: Add actions for removing tabs to browser-state

parent 16a49583
......@@ -187,6 +187,9 @@ class SessionManager(
*/
fun removeSessions() {
delegate.removeSessions()
store?.syncDispatch(
TabListAction.RemoveAllTabsAction
)
}
/**
......@@ -194,6 +197,12 @@ class SessionManager(
*/
fun removeAll() {
delegate.removeAll()
store?.syncDispatch(
TabListAction.RemoveAllTabsAction
)
store?.syncDispatch(
CustomTabListAction.RemoveAllCustomTabsAction
)
}
/**
......
......@@ -57,6 +57,49 @@ class SessionManagerMigrationTest {
assertEquals("https://www.firefox.com", store.state.tabs[0].content.url)
}
@Test
fun `Remove all regular sessions`() {
val store = BrowserStore()
val sessionManager = SessionManager(engine = mock(), store = store)
sessionManager.add(Session("https://www.mozilla.org"))
sessionManager.add(Session("https://www.firefox.com"))
sessionManager.add(Session("https://www.getpocket.com").apply { customTabConfig = mock() })
assertEquals(2, sessionManager.sessions.size)
assertEquals(3, sessionManager.all.size)
assertEquals(2, store.state.tabs.size)
assertEquals(1, store.state.customTabs.size)
sessionManager.removeSessions()
assertEquals(0, sessionManager.sessions.size)
assertEquals(1, sessionManager.all.size)
assertEquals(0, store.state.tabs.size)
assertEquals(1, store.state.customTabs.size)
}
@Test
fun `Remove all custom tab and regular sessions`() {
val store = BrowserStore()
val sessionManager = SessionManager(engine = mock(), store = store)
sessionManager.add(Session("https://www.mozilla.org"))
sessionManager.add(Session("https://www.firefox.com").apply {
customTabConfig = mock()
})
assertEquals(2, sessionManager.all.size)
assertEquals(1, store.state.tabs.size)
assertEquals(1, store.state.customTabs.size)
sessionManager.removeAll()
assertTrue(sessionManager.sessions.isEmpty())
assertTrue(store.state.tabs.isEmpty())
assertTrue(store.state.customTabs.isEmpty())
}
@Test
fun `Selecting session`() {
val store = BrowserStore()
......
......@@ -39,6 +39,21 @@ sealed class TabListAction : BrowserAction() {
* Restores state from a (partial) previous state.
*/
data class RestoreAction(val tabs: List<TabSessionState>, val selectedTabId: String? = null) : TabListAction()
/**
* Removes both private and normal [TabSessionState]s.
*/
object RemoveAllTabsAction : TabListAction()
/**
* Removes all private [TabSessionState]s.
*/
object RemoveAllPrivateTabsAction : TabListAction()
/**
* Removes all non-private [TabSessionState]s.
*/
object RemoveAllNormalTabsAction : TabListAction()
}
/**
......@@ -54,6 +69,11 @@ sealed class CustomTabListAction : BrowserAction() {
* Removes an existing [CustomTabSessionState] to [BrowserState.customTabs].
*/
data class RemoveCustomTabAction(val tabId: String) : CustomTabListAction()
/**
* Removes all custom tabs [TabSessionState]s.
*/
object RemoveAllCustomTabsAction : CustomTabListAction()
}
/**
......
......@@ -20,6 +20,10 @@ internal object CustomTabListReducer {
val tab = state.findCustomTab(action.tabId) ?: return state
state.copy(customTabs = state.customTabs - tab)
}
is CustomTabListAction.RemoveAllCustomTabsAction -> {
state.copy(customTabs = emptyList())
}
}
}
}
......@@ -6,6 +6,7 @@ package mozilla.components.browser.state.reducer
import mozilla.components.browser.state.action.TabListAction
import mozilla.components.browser.state.selector.findTab
import mozilla.components.browser.state.selector.selectedTab
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.TabSessionState
import kotlin.math.max
......@@ -68,6 +69,42 @@ internal object TabListReducer {
}
)
}
is TabListAction.RemoveAllTabsAction -> {
state.copy(
tabs = emptyList(),
selectedTabId = null
)
}
is TabListAction.RemoveAllPrivateTabsAction -> {
val selectionAffected = state.selectedTab?.content?.private == true
val updatedTabs = state.tabs.filterNot { it.content.private }
state.copy(
tabs = updatedTabs,
selectedTabId = if (selectionAffected && updatedTabs.isNotEmpty()) {
// If the selection is affected, select the last normal tab, if available.
updatedTabs.last().id
} else {
state.selectedTabId
}
)
}
is TabListAction.RemoveAllNormalTabsAction -> {
val selectionAffected = state.selectedTab?.content?.private == false
val updatedTabs = state.tabs.filter { it.content.private }
state.copy(
tabs = updatedTabs,
selectedTabId = if (selectionAffected) {
// If the selection is affected, we'll set it to null as there's no
// normal tab left and NO private tab should get selected instead.
null
} else {
state.selectedTabId
}
)
}
}
}
}
......
......@@ -6,6 +6,7 @@ package mozilla.components.browser.state.action
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.createCustomTab
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.test.ext.joinBlocking
import org.junit.Assert.assertEquals
......@@ -60,4 +61,21 @@ class CustomTabListActionTest {
assertEquals(customTab1, store.state.customTabs[0])
assertEquals(customTab2, store.state.customTabs[1])
}
@Test
fun `RemoveAllCustomTabsAction - Removes all custom tabs (but not regular tabs)`() {
val customTab1 = createCustomTab("https://www.mozilla.org")
val customTab2 = createCustomTab("https://www.firefox.com")
val regularTab = createTab(url = "https://www.mozilla.org")
val state = BrowserState(customTabs = listOf(customTab1, customTab2), tabs = listOf(regularTab))
val store = BrowserStore(state)
assertEquals(2, store.state.customTabs.size)
assertEquals(1, store.state.tabs.size)
store.dispatch(CustomTabListAction.RemoveAllCustomTabsAction).joinBlocking()
assertEquals(0, store.state.customTabs.size)
assertEquals(1, store.state.tabs.size)
}
}
......@@ -11,6 +11,7 @@ import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.test.ext.joinBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
class TabListActionTest {
......@@ -340,22 +341,26 @@ class TabListActionTest {
@Test
fun `RestoreAction - Does not update selection if none was provided`() {
val store = BrowserStore(BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
val store = BrowserStore(
BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
)
)
))
)
assertEquals(2, store.state.tabs.size)
store.dispatch(TabListAction.RestoreAction(
tabs = listOf(
createTab(id = "c", url = "https://www.example.org", private = true),
createTab(id = "d", url = "https://getpocket.com", private = false)
),
selectedTabId = null
)).joinBlocking()
store.dispatch(
TabListAction.RestoreAction(
tabs = listOf(
createTab(id = "c", url = "https://www.example.org", private = true),
createTab(id = "d", url = "https://getpocket.com", private = false)
),
selectedTabId = null
)
).joinBlocking()
assertEquals(4, store.state.tabs.size)
assertEquals("c", store.state.tabs[0].id)
......@@ -364,4 +369,123 @@ class TabListActionTest {
assertEquals("b", store.state.tabs[3].id)
assertNull(store.state.selectedTabId)
}
@Test
fun `RemoveAllTabsAction - Removes both private and non-private tabs (but not custom tabs)`() {
val state = BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
),
customTabs = listOf(
createCustomTab(id = "a1", url = "https://www.firefox.com")
),
selectedTabId = "a"
)
val store = BrowserStore(state)
store.dispatch(TabListAction.RemoveAllTabsAction).joinBlocking()
assertTrue(store.state.tabs.isEmpty())
assertNull(store.state.selectedTabId)
assertEquals(1, store.state.customTabs.size)
assertEquals("a1", store.state.customTabs.last().id)
}
@Test
fun `RemoveAllPrivateTabsAction - Removes only private tabs`() {
val state = BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
),
customTabs = listOf(
createCustomTab(id = "a1", url = "https://www.firefox.com")
),
selectedTabId = "a"
)
val store = BrowserStore(state)
store.dispatch(TabListAction.RemoveAllPrivateTabsAction).joinBlocking()
assertEquals(1, store.state.tabs.size)
assertEquals("a", store.state.tabs[0].id)
assertEquals("a", store.state.selectedTabId)
assertEquals(1, store.state.customTabs.size)
assertEquals("a1", store.state.customTabs.last().id)
}
@Test
fun `RemoveAllPrivateTabsAction - Updates selection if affected`() {
val state = BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
),
customTabs = listOf(
createCustomTab(id = "a1", url = "https://www.firefox.com")
),
selectedTabId = "b"
)
val store = BrowserStore(state)
store.dispatch(TabListAction.RemoveAllPrivateTabsAction).joinBlocking()
assertEquals(1, store.state.tabs.size)
assertEquals("a", store.state.tabs[0].id)
assertEquals("a", store.state.selectedTabId)
assertEquals(1, store.state.customTabs.size)
assertEquals("a1", store.state.customTabs.last().id)
}
@Test
fun `RemoveAllNormalTabsAction - Removes only normal (non-private) tabs`() {
val state = BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
),
customTabs = listOf(
createCustomTab(id = "a1", url = "https://www.firefox.com")
),
selectedTabId = "b"
)
val store = BrowserStore(state)
store.dispatch(TabListAction.RemoveAllNormalTabsAction).joinBlocking()
assertEquals(1, store.state.tabs.size)
assertEquals("b", store.state.tabs[0].id)
assertEquals("b", store.state.selectedTabId)
assertEquals(1, store.state.customTabs.size)
assertEquals("a1", store.state.customTabs.last().id)
}
@Test
fun `RemoveAllNormalTabsAction - Updates selection if affected`() {
val state = BrowserState(
tabs = listOf(
createTab(id = "a", url = "https://www.mozilla.org", private = false),
createTab(id = "b", url = "https://www.firefox.com", private = true)
),
customTabs = listOf(
createCustomTab(id = "a1", url = "https://www.firefox.com")
),
selectedTabId = "a"
)
val store = BrowserStore(state)
store.dispatch(TabListAction.RemoveAllNormalTabsAction).joinBlocking()
assertEquals(1, store.state.tabs.size)
assertEquals("b", store.state.tabs[0].id)
// After removing the last normal tab NO private tab should get selected
assertNull(store.state.selectedTabId)
assertEquals(1, store.state.customTabs.size)
assertEquals("a1", store.state.customTabs.last().id)
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment