[fenix] For https://github.com/mozilla-mobile/fenix/issues/18515 - Added Icon and sync functionality

Co-authored-by: Jonathan Almeida <jalmeida@mozilla.com>
pull/600/head
codrut.topliceanu 3 years ago committed by Jonathan Almeida
parent 695c777306
commit dc1f62eb6e

@ -0,0 +1,93 @@
/* 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
import androidx.appcompat.content.res.AppCompatResources
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
import org.mozilla.fenix.R
import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor
import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsInteractor
class FloatingActionButtonBinding(
private val store: TabsTrayStore,
private val actionButton: ExtendedFloatingActionButton,
private val browserTrayInteractor: BrowserTrayInteractor,
private val syncedTabsInteractor: SyncedTabsInteractor
) : LifecycleAwareFeature {
private var scope: CoroutineScope? = null
@OptIn(ExperimentalCoroutinesApi::class)
override fun start() {
setFab(store.state.selectedPage, store.state.syncing)
scope = store.flowScoped { flow ->
flow.map { it }
.ifAnyChanged { state ->
arrayOf(
state.selectedPage,
state.syncing
)
}
.collect { state ->
setFab(state.selectedPage, state.syncing)
}
}
}
override fun stop() {
scope?.cancel()
}
private fun setFab(selectedPage: Page, syncing: Boolean) {
when (selectedPage) {
Page.NormalTabs -> {
actionButton.apply {
shrink()
show()
icon = AppCompatResources.getDrawable(context, R.drawable.ic_new)
setOnClickListener {
browserTrayInteractor.onFabClicked(false)
}
}
}
Page.PrivateTabs -> {
actionButton.apply {
text = context.getText(R.string.tab_drawer_fab_content)
extend()
show()
icon = AppCompatResources.getDrawable(context, R.drawable.ic_new)
setOnClickListener {
browserTrayInteractor.onFabClicked(true)
}
}
}
Page.SyncedTabs -> {
actionButton.apply {
text = if (syncing) context.getText(R.string.sync_syncing_in_progress)
else context.getText(R.string.tab_drawer_fab_sync)
extend()
show()
icon = AppCompatResources.getDrawable(context, R.drawable.ic_fab_sync)
setOnClickListener {
// Notify the store observers (one of which is the SyncedTabsFeature), that
// a sync was requested.
if (!syncing) {
store.dispatch(TabsTrayAction.SyncNow)
syncedTabsInteractor.onRefresh()
}
}
}
}
}
}
}

@ -18,11 +18,12 @@ import org.mozilla.fenix.tabstray.TrayPagerAdapter.Companion.POSITION_PRIVATE_TA
*/ */
class TabLayoutMediator( class TabLayoutMediator(
private val tabLayout: TabLayout, private val tabLayout: TabLayout,
private val interactor: TabsTrayInteractor, interactor: TabsTrayInteractor,
private val store: BrowserStore private val browserStore: BrowserStore,
trayStore: TabsTrayStore
) : LifecycleAwareFeature { ) : LifecycleAwareFeature {
private val observer = TabLayoutObserver(interactor) private val observer = TabLayoutObserver(interactor, trayStore)
/** /**
* Start observing the [TabLayout] and select the current tab for initial state. * Start observing the [TabLayout] and select the current tab for initial state.
@ -39,7 +40,7 @@ class TabLayoutMediator(
@VisibleForTesting @VisibleForTesting
internal fun selectActivePage() { internal fun selectActivePage() {
val selectedTab = store.state.selectedTab ?: return val selectedTab = browserStore.state.selectedTab ?: return
val selectedPagerPosition = if (selectedTab.content.private) { val selectedPagerPosition = if (selectedTab.content.private) {
POSITION_PRIVATE_TABS POSITION_PRIVATE_TABS
@ -55,7 +56,8 @@ class TabLayoutMediator(
* An observer for the [TabLayout] used for the Tabs Tray. * An observer for the [TabLayout] used for the Tabs Tray.
*/ */
internal class TabLayoutObserver( internal class TabLayoutObserver(
private val interactor: TabsTrayInteractor private val interactor: TabsTrayInteractor,
private val trayStore: TabsTrayStore
) : TabLayout.OnTabSelectedListener { ) : TabLayout.OnTabSelectedListener {
private var initialScroll = true private var initialScroll = true
@ -70,8 +72,16 @@ internal class TabLayoutObserver(
} }
interactor.setCurrentTrayPosition(tab.position, animate) interactor.setCurrentTrayPosition(tab.position, animate)
trayStore.dispatch(TabsTrayAction.PageSelected(tab.toPage()))
} }
override fun onTabUnselected(tab: TabLayout.Tab) = Unit override fun onTabUnselected(tab: TabLayout.Tab) = Unit
override fun onTabReselected(tab: TabLayout.Tab) = Unit override fun onTabReselected(tab: TabLayout.Tab) = Unit
} }
fun TabLayout.Tab.toPage() = when (this.position) {
0 -> Page.NormalTabs
1 -> Page.PrivateTabs
else -> Page.SyncedTabs
}

@ -5,8 +5,15 @@
package org.mozilla.fenix.tabstray package org.mozilla.fenix.tabstray
import androidx.navigation.NavController import androidx.navigation.NavController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import mozilla.components.concept.base.profiler.Profiler
import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.sync.SyncReason
import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.tabtray.TabTrayDialogFragmentDirections import org.mozilla.fenix.tabtray.TabTrayDialogFragmentDirections
interface TabsTrayController { interface TabsTrayController {
@ -15,15 +22,48 @@ interface TabsTrayController {
* Called when user clicks the new tab button. * Called when user clicks the new tab button.
*/ */
fun onNewTabTapped(isPrivate: Boolean) fun onNewTabTapped(isPrivate: Boolean)
/**
* Starts user account tab syncing.
* */
fun onSyncStarted()
} }
class DefaultTabsTrayController( class DefaultTabsTrayController(
private val store: TabsTrayStore,
private val browsingModeManager: BrowsingModeManager, private val browsingModeManager: BrowsingModeManager,
private val navController: NavController private val navController: NavController,
private val profiler: Profiler?,
private val dismissTabTray: () -> Unit,
private val metrics: MetricController,
private val ioScope: CoroutineScope,
private val accountManager: FxaAccountManager
) : TabsTrayController { ) : TabsTrayController {
override fun onNewTabTapped(isPrivate: Boolean) { override fun onNewTabTapped(isPrivate: Boolean) {
val startTime = profiler?.getProfilerTime()
browsingModeManager.mode = BrowsingMode.fromBoolean(isPrivate) browsingModeManager.mode = BrowsingMode.fromBoolean(isPrivate)
navController.navigate(TabTrayDialogFragmentDirections.actionGlobalHome(focusOnAddressBar = true)) navController.navigate(TabTrayDialogFragmentDirections.actionGlobalHome(focusOnAddressBar = true))
dismissTabTray()
profiler?.addMarker(
"DefaultTabTrayController.onNewTabTapped",
startTime
)
}
override fun onSyncStarted() {
ioScope.launch {
metrics.track(Event.SyncAccountSyncNow)
// Trigger a sync.
accountManager.syncNow(SyncReason.User)
// Poll for device events & update devices.
accountManager.authenticatedAccount()
?.deviceConstellation()?.run {
refreshDevices()
pollForCommands()
}
}.invokeOnCompletion {
store.dispatch(TabsTrayAction.SyncCompleted)
}
} }
} }

@ -12,25 +12,24 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.android.synthetic.main.component_tabstray2.* import kotlinx.android.synthetic.main.component_tabstray2.*
import kotlinx.android.synthetic.main.component_tabstray2.view.* import kotlinx.android.synthetic.main.component_tabstray2.view.*
import kotlinx.android.synthetic.main.component_tabstray_fab.*
import kotlinx.android.synthetic.main.tabs_tray_tab_counter2.* import kotlinx.android.synthetic.main.tabs_tray_tab_counter2.*
import kotlinx.android.synthetic.main.component_tabstray2.tab_layout import kotlinx.coroutines.Dispatchers
import kotlinx.android.synthetic.main.component_tabstray2.tabsTray
import kotlinx.android.synthetic.main.component_tabstray2.view.tab_wrapper
import kotlinx.android.synthetic.main.component_tabstray_fab.view.new_tab_button
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.plus
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.home.HomeScreenViewModel import org.mozilla.fenix.home.HomeScreenViewModel
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor
import org.mozilla.fenix.tabstray.browser.DefaultBrowserTrayInteractor import org.mozilla.fenix.tabstray.browser.DefaultBrowserTrayInteractor
import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsInteractor import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsInteractor
@ -42,10 +41,10 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
private lateinit var browserTrayInteractor: BrowserTrayInteractor private lateinit var browserTrayInteractor: BrowserTrayInteractor
private lateinit var tabsTrayController: DefaultTabsTrayController private lateinit var tabsTrayController: DefaultTabsTrayController
private lateinit var behavior: BottomSheetBehavior<ConstraintLayout> private lateinit var behavior: BottomSheetBehavior<ConstraintLayout>
private var hasAccessibilityEnabled: Boolean = false
private val tabLayoutMediator = ViewBoundFeatureWrapper<TabLayoutMediator>() private val tabLayoutMediator = ViewBoundFeatureWrapper<TabLayoutMediator>()
private val tabCounterBinding = ViewBoundFeatureWrapper<TabCounterBinding>() private val tabCounterBinding = ViewBoundFeatureWrapper<TabCounterBinding>()
private val floatingActionButtonBinding = ViewBoundFeatureWrapper<FloatingActionButtonBinding>()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -78,14 +77,19 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val activity = activity as HomeActivity val activity = activity as HomeActivity
hasAccessibilityEnabled = activity.settings().accessibilityServicesEnabled
tabsTrayController = DefaultTabsTrayController( tabsTrayController = DefaultTabsTrayController(
store = tabsTrayStore,
browsingModeManager = activity.browsingModeManager, browsingModeManager = activity.browsingModeManager,
navController = findNavController() navController = findNavController(),
dismissTabTray = ::dismissAllowingStateLoss,
profiler = requireComponents.core.engine.profiler,
accountManager = requireComponents.backgroundServices.accountManager,
metrics = requireComponents.analytics.metrics,
ioScope = lifecycleScope + Dispatchers.IO
) )
val browserTrayInteractor = DefaultBrowserTrayInteractor( browserTrayInteractor = DefaultBrowserTrayInteractor(
tabsTrayStore, tabsTrayStore,
this@TabsTrayFragment, this@TabsTrayFragment,
tabsTrayController, tabsTrayController,
@ -106,7 +110,8 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
val syncedTabsTrayInteractor = SyncedTabsInteractor( val syncedTabsTrayInteractor = SyncedTabsInteractor(
requireComponents.analytics.metrics, requireComponents.analytics.metrics,
requireActivity() as HomeActivity, requireActivity() as HomeActivity,
this this,
controller = tabsTrayController
) )
setupMenu(view, navigationInteractor) setupMenu(view, navigationInteractor)
@ -122,7 +127,8 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
feature = TabLayoutMediator( feature = TabLayoutMediator(
tabLayout = tab_layout, tabLayout = tab_layout,
interactor = this, interactor = this,
store = requireComponents.core.store browserStore = requireComponents.core.store,
trayStore = tabsTrayStore
), owner = this, ), owner = this,
view = view view = view
) )
@ -135,11 +141,21 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
owner = this, owner = this,
view = view view = view
) )
floatingActionButtonBinding.set(
feature = FloatingActionButtonBinding(
store = tabsTrayStore,
actionButton = new_tab_button,
browserTrayInteractor = browserTrayInteractor,
syncedTabsInteractor = syncedTabsTrayInteractor
),
owner = this,
view = view
)
} }
override fun setCurrentTrayPosition(position: Int, smoothScroll: Boolean) { override fun setCurrentTrayPosition(position: Int, smoothScroll: Boolean) {
tabsTray.setCurrentItem(position, smoothScroll) tabsTray.setCurrentItem(position, smoothScroll)
setupNewTabButtons(tabsTray.currentItem)
} }
override fun navigateToBrowser() { override fun navigateToBrowser() {
@ -209,42 +225,4 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
findNavController().navigate(directions) findNavController().navigate(directions)
dismissAllowingStateLoss() dismissAllowingStateLoss()
} }
private fun setupNewTabButtons(currentPage: Int) {
fabView?.let { fabView ->
when (currentPage) {
NORMAL -> {
fabView.new_tab_button.shrink()
fabView.new_tab_button.show()
fabView.new_tab_button.setOnClickListener {
browserTrayInteractor.onFabClicked(false)
}
}
PRIVATE -> {
fabView.new_tab_button.text =
requireContext().resources.getText(R.string.tab_drawer_fab_content)
fabView.new_tab_button.extend()
fabView.new_tab_button.show()
fabView.new_tab_button.setOnClickListener {
browserTrayInteractor.onFabClicked(true)
}
}
SYNC -> {
fabView.new_tab_button.text =
requireContext().resources.getText(R.string.preferences_sync_now)
fabView.new_tab_button.extend()
fabView.new_tab_button.show()
fabView.new_tab_button.setOnClickListener {
}
}
}
}
}
companion object {
// TabsTray Pages
const val NORMAL = 0
const val PRIVATE = 1
const val SYNC = 2
}
} }

@ -10,14 +10,18 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.tabstray.TabsTrayController
import org.mozilla.fenix.tabstray.TabsTrayInteractor import org.mozilla.fenix.tabstray.TabsTrayInteractor
internal class SyncedTabsInteractor( class SyncedTabsInteractor(
private val metrics: MetricController, private val metrics: MetricController,
private val activity: HomeActivity, private val activity: HomeActivity,
private val trayInteractor: TabsTrayInteractor private val trayInteractor: TabsTrayInteractor,
private val controller: TabsTrayController
) : SyncedTabsView.Listener { ) : SyncedTabsView.Listener {
override fun onRefresh() = Unit override fun onRefresh() {
controller.onSyncStarted()
}
override fun onTabClicked(tab: Tab) { override fun onTabClicked(tab: Tab) {
metrics.track(Event.SyncedTabOpened) metrics.track(Event.SyncedTabOpened)
activity.openToBrowserAndLoad( activity.openToBrowserAndLoad(

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="14"
android:viewportHeight="14">
<group
android:pivotX="7"
android:pivotY="7"
android:scaleX="0.8"
android:scaleY="0.8">
<path
android:fillColor="#ffffff"
android:fillType="evenOdd"
android:pathData="M12,1C12,0.4477 12.4477,0 13,0C13.5523,0 14,0.4477 14,1V5C14,5.5523 13.5523,6 13,6H9C8.4477,6 8,5.5523 8,5C8,4.4477 8.4477,4 9,4H10.967C10.0382,2.7401 8.5652,1.9976 7,2C4.7088,2.0026 2.7146,3.5672 2.167,5.792C2.0256,6.319 1.4879,6.6353 0.9586,6.503C0.4293,6.3707 0.1038,5.8385 0.227,5.307C0.8267,2.8397 2.7245,0.896 5.1768,0.2376C7.629,-0.4208 10.2451,0.3109 12,2.146V1ZM11.833,8.208C11.9668,7.6724 12.5093,7.3465 13.045,7.48C13.3024,7.5442 13.5238,7.7081 13.6603,7.9356C13.7969,8.1632 13.8374,8.4356 13.773,8.693C13.1733,11.1603 11.2755,13.104 8.8232,13.7624C6.371,14.4208 3.7548,13.6891 2,11.854V13C2,13.5523 1.5523,14 1,14C0.4477,14 0,13.5523 0,13V9C0,8.4477 0.4477,8 1,8H5C5.5523,8 6,8.4477 6,9C6,9.5523 5.5523,10 5,10H3.033C3.9618,11.2598 5.4348,12.0025 7,12C9.2912,11.9974 11.2854,10.4328 11.833,8.208Z" />
</group>
</vector>

@ -598,6 +598,8 @@
<string name="add_private_tab">Add private tab</string> <string name="add_private_tab">Add private tab</string>
<!-- Text for the new tab button to indicate adding a new private tab in the tab --> <!-- Text for the new tab button to indicate adding a new private tab in the tab -->
<string name="tab_drawer_fab_content">Private</string> <string name="tab_drawer_fab_content">Private</string>
<!-- Text for the new tab button to indicate syncing command on the synced tabs page -->
<string name="tab_drawer_fab_sync">Sync</string>
<!-- Text shown as the title of the open tab tray --> <!-- Text shown as the title of the open tab tray -->
<string name="tab_tray_title">Open Tabs</string> <string name="tab_tray_title">Open Tabs</string>
<!-- Text shown in the menu for saving tabs to a collection --> <!-- Text shown in the menu for saving tabs to a collection -->

@ -23,10 +23,10 @@ class TabLayoutMediatorTest {
@Test @Test
fun `page to normal tab position when selected tab is also normal`() { fun `page to normal tab position when selected tab is also normal`() {
val store = createState("123") val store = createStore("123")
val tabLayout: TabLayout = mockk(relaxed = true) val tabLayout: TabLayout = mockk(relaxed = true)
val tab: TabLayout.Tab = mockk(relaxed = true) val tab: TabLayout.Tab = mockk(relaxed = true)
val mediator = TabLayoutMediator(tabLayout, mockk(relaxed = true), store) val mediator = TabLayoutMediator(tabLayout, mockk(relaxed = true), store, mockk())
every { tabLayout.getTabAt(POSITION_NORMAL_TABS) }.answers { tab } every { tabLayout.getTabAt(POSITION_NORMAL_TABS) }.answers { tab }
@ -37,10 +37,10 @@ class TabLayoutMediatorTest {
@Test @Test
fun `page to private tab position when selected tab is also private`() { fun `page to private tab position when selected tab is also private`() {
val store = createState("456") val store = createStore("456")
val tabLayout: TabLayout = mockk(relaxed = true) val tabLayout: TabLayout = mockk(relaxed = true)
val tab: TabLayout.Tab = mockk(relaxed = true) val tab: TabLayout.Tab = mockk(relaxed = true)
val mediator = TabLayoutMediator(tabLayout, mockk(relaxed = true), store) val mediator = TabLayoutMediator(tabLayout, mockk(relaxed = true), store, mockk())
every { tabLayout.getTabAt(POSITION_PRIVATE_TABS) }.answers { tab } every { tabLayout.getTabAt(POSITION_PRIVATE_TABS) }.answers { tab }
@ -51,9 +51,9 @@ class TabLayoutMediatorTest {
@Test @Test
fun `lifecycle methods adds and removes observer`() { fun `lifecycle methods adds and removes observer`() {
val store = createState("456") val store = createStore("456")
val tabLayout: TabLayout = mockk(relaxed = true) val tabLayout: TabLayout = mockk(relaxed = true)
val mediator = TabLayoutMediator(tabLayout, mockk(relaxed = true), store) val mediator = TabLayoutMediator(tabLayout, mockk(relaxed = true), store, mockk())
mediator.start() mediator.start()
@ -64,7 +64,7 @@ class TabLayoutMediatorTest {
verify { tabLayout.removeOnTabSelectedListener(any()) } verify { tabLayout.removeOnTabSelectedListener(any()) }
} }
private fun createState(selectedId: String) = BrowserStore( private fun createStore(selectedId: String) = BrowserStore(
initialState = BrowserState( initialState = BrowserState(
tabs = listOf( tabs = listOf(
TabSessionState( TabSessionState(

@ -8,25 +8,43 @@ import com.google.android.material.tabs.TabLayout
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify import io.mockk.verify
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.middleware.CaptureActionsMiddleware
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test import org.junit.Test
class TabLayoutObserverTest { class TabLayoutObserverTest {
private val interactor = mockk<TabsTrayInteractor>(relaxed = true) private val interactor = mockk<TabsTrayInteractor>(relaxed = true)
private lateinit var store: TabsTrayStore
private val middleware = CaptureActionsMiddleware<TabsTrayState, TabsTrayAction>()
@Before
fun setup() {
store = TabsTrayStore(middlewares = listOf(middleware))
}
@Test @Test
fun `WHEN tab is selected THEN notify the interactor`() { fun `WHEN tab is selected THEN notify the interactor`() {
val observer = TabLayoutObserver(interactor) val observer = TabLayoutObserver(interactor, store)
val tab = mockk<TabLayout.Tab>() val tab = mockk<TabLayout.Tab>()
every { tab.position } returns 1 every { tab.position } returns 1
observer.onTabSelected(tab) observer.onTabSelected(tab)
store.waitUntilIdle()
verify { interactor.setCurrentTrayPosition(1, false) } verify { interactor.setCurrentTrayPosition(1, false) }
middleware.assertLastAction(TabsTrayAction.PageSelected::class) {
assertTrue(it.page == Page.PrivateTabs)
}
} }
@Test @Test
fun `WHEN observer is first started THEN do not smooth scroll`() { fun `WHEN observer is first started THEN do not smooth scroll`() {
val observer = TabLayoutObserver(interactor) val store = TabsTrayStore()
val observer = TabLayoutObserver(interactor, store)
val tab = mockk<TabLayout.Tab>() val tab = mockk<TabLayout.Tab>()
every { tab.position } returns 1 every { tab.position } returns 1

@ -32,7 +32,8 @@ class DefaultBrowserTrayInteractorTest {
@Test @Test
fun `WHEN pager position is synced tabs THEN return a list layout manager`() { fun `WHEN pager position is synced tabs THEN return a list layout manager`() {
val interactor = DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), mockk(), mockk()) val interactor =
DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), mockk(), mockk(), mockk())
val result = interactor.getLayoutManagerForPosition( val result = interactor.getLayoutManagerForPosition(
mockk(), mockk(),
@ -46,7 +47,8 @@ class DefaultBrowserTrayInteractorTest {
fun `WHEN setting is grid view THEN return grid layout manager`() { fun `WHEN setting is grid view THEN return grid layout manager`() {
val context = mockk<Context>() val context = mockk<Context>()
val settings = mockk<Settings>() val settings = mockk<Settings>()
val interactor = DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), settings, mockk()) val interactor =
DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), mockk(), settings, mockk())
every { context.numberOfGridColumns }.answers { 4 } every { context.numberOfGridColumns }.answers { 4 }
every { settings.gridTabView }.answers { true } every { settings.gridTabView }.answers { true }
@ -63,7 +65,8 @@ class DefaultBrowserTrayInteractorTest {
fun `WHEN setting is list view THEN return list layout manager`() { fun `WHEN setting is list view THEN return list layout manager`() {
val context = mockk<Context>() val context = mockk<Context>()
val settings = mockk<Settings>() val settings = mockk<Settings>()
val interactor = DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), settings, mockk()) val interactor =
DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), mockk(), settings, mockk())
every { context.numberOfGridColumns }.answers { 4 } every { context.numberOfGridColumns }.answers { 4 }
every { settings.gridTabView }.answers { false } every { settings.gridTabView }.answers { false }

Loading…
Cancel
Save