Issue #20663: Make inactive card collapsible
We use make the inactive tabs section of the tabstray collapsible in this change, with a technical quirk: we want to make the "isExpanded" state of the tabs stay for the lifetime of the app and not the tabs tray, but this functionality does not exist. In this patch, we're storing the UI state in a singleton class that exists for the lifetime of the app, but a more concrete solution is to use an AppStore that holds content like this, which we can land in a future patch.upstream-sync
parent
0bc64e8ca8
commit
d6bc93981d
@ -0,0 +1,28 @@
|
||||
/* 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 org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.tabstray.TabsTray
|
||||
import mozilla.components.feature.tabs.ext.toTabs
|
||||
|
||||
class InactiveTabsController(
|
||||
private val browserStore: BrowserStore,
|
||||
private val tabFilter: (TabSessionState) -> Boolean,
|
||||
private val tray: TabsTray
|
||||
) {
|
||||
/**
|
||||
* Updates the inactive card to be expanded to display all the tabs, or collapsed with only
|
||||
* the title showing.
|
||||
*/
|
||||
fun updateCardExpansion(isExpanded: Boolean) {
|
||||
InactiveTabsState.isExpanded = isExpanded
|
||||
|
||||
val tabs = browserStore.state.toTabs { tabFilter.invoke(it) }
|
||||
|
||||
tray.updateTabs(tabs)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/* 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 org.mozilla.fenix.tabstray.browser
|
||||
|
||||
interface InactiveTabsInteractor {
|
||||
fun onHeaderClicked(activated: Boolean)
|
||||
}
|
||||
|
||||
class DefaultInactiveTabsInteractor(
|
||||
private val controller: InactiveTabsController
|
||||
) : InactiveTabsInteractor {
|
||||
override fun onHeaderClicked(activated: Boolean) {
|
||||
controller.updateCardExpansion(activated)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An experimental state holder for [InactiveTabsAdapter] that lives at the application lifetime.
|
||||
*
|
||||
* TODO This should be replaced with the AppStore.
|
||||
*/
|
||||
object InactiveTabsState {
|
||||
var isExpanded = true
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* 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 org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultInactiveTabsInteractorTest {
|
||||
|
||||
@Test
|
||||
fun `WHEN onHeaderClicked THEN updateCardExpansion`() {
|
||||
val controller: InactiveTabsController = mockk(relaxed = true)
|
||||
val interactor = DefaultInactiveTabsInteractor(controller)
|
||||
|
||||
interactor.onHeaderClicked(true)
|
||||
|
||||
verify { controller.updateCardExpansion(true) }
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/* 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 org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.HeaderHolder
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class InactiveTabViewHolderTest {
|
||||
@Test
|
||||
fun `HeaderHolder - WHEN clicked THEN notify the interactor`() {
|
||||
val view = LayoutInflater.from(testContext).inflate(HeaderHolder.LAYOUT_ID, null)
|
||||
val interactor: InactiveTabsInteractor = mockk(relaxed = true)
|
||||
val viewHolder = HeaderHolder(view, interactor)
|
||||
|
||||
val initialActivatedState = view.isActivated
|
||||
|
||||
viewHolder.itemView.performClick()
|
||||
|
||||
verify { interactor.onHeaderClicked(any()) }
|
||||
|
||||
assertEquals(!initialActivatedState, view.isActivated)
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/* 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 org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.state.state.BrowserState
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.tabstray.Tabs
|
||||
import mozilla.components.concept.tabstray.TabsTray
|
||||
import org.junit.Assert.assertEquals
|
||||
import mozilla.components.browser.state.state.createTab as createTabState
|
||||
import org.junit.Test
|
||||
|
||||
class InactiveTabsControllerTest {
|
||||
@Test
|
||||
fun `WHEN expanded THEN notify filtered card`() {
|
||||
val filter: (TabSessionState) -> Boolean = { !it.content.private }
|
||||
val store = BrowserStore(
|
||||
BrowserState(
|
||||
tabs = listOf(
|
||||
createTabState("https://mozilla.org", id = "1"),
|
||||
createTabState("https://firefox.com", id = "2"),
|
||||
createTabState("https://getpocket.com", id = "3", private = true)
|
||||
)
|
||||
)
|
||||
)
|
||||
val tray: TabsTray = mockk(relaxed = true)
|
||||
val tabsSlot = slot<Tabs>()
|
||||
val controller = InactiveTabsController(store, filter, tray)
|
||||
|
||||
controller.updateCardExpansion(true)
|
||||
|
||||
verify { tray.updateTabs(capture(tabsSlot)) }
|
||||
|
||||
assertEquals(2, tabsSlot.captured.list.size)
|
||||
assertEquals("1", tabsSlot.captured.list.first().id)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue