No issue: Move menu to separate integrations class

upstream-sync
Jonathan Almeida 3 years ago committed by Jonathan Almeida
parent dd3e95b4cf
commit 2e3086ac40

@ -0,0 +1,73 @@
/* 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 android.content.Context
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.cardview.widget.CardView
import androidx.core.content.ContextCompat
import com.google.android.material.tabs.TabLayout
import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.menu.BrowserMenuBuilder
import mozilla.components.browser.state.store.BrowserStore
import org.mozilla.fenix.R
/**
* A wrapper class that building the tabs tray menu that handles item clicks.
*/
class MenuIntegration(
private val context: Context,
private val browserStore: BrowserStore,
private val tabsTrayStore: TabsTrayStore,
private val tabLayout: TabLayout,
private val navigationInteractor: NavigationInteractor
) {
private val tabsTrayItemMenu by lazy {
TabsTrayMenu(
context = context,
browserStore = browserStore,
tabLayout = tabLayout,
onItemTapped = ::handleMenuClicked
)
}
private val isPrivateMode: Boolean
get() = tabsTrayStore.state.selectedPage == Page.PrivateTabs
/**
* Builds the internal menu items list. See [BrowserMenuBuilder.build].
*/
fun build() = tabsTrayItemMenu.menuBuilder.build(context)
@VisibleForTesting
internal fun handleMenuClicked(item: TabsTrayMenu.Item) = when (item) {
is TabsTrayMenu.Item.ShareAllTabs ->
navigationInteractor.onShareTabsOfTypeClicked(isPrivateMode)
is TabsTrayMenu.Item.OpenTabSettings ->
navigationInteractor.onTabSettingsClicked()
is TabsTrayMenu.Item.CloseAllTabs ->
navigationInteractor.onCloseAllTabsClicked(isPrivateMode)
is TabsTrayMenu.Item.OpenRecentlyClosed ->
navigationInteractor.onOpenRecentlyClosedClicked()
is TabsTrayMenu.Item.SelectTabs -> {
/* TODO implement when mulitiselect call is available */
}
}
}
/**
* Invokes [BrowserMenu.show] and applies the default theme color background.
*/
fun BrowserMenu.showWithTheme(view: View) {
show(view).also { popupMenu ->
(popupMenu.contentView as? CardView)?.setCardBackgroundColor(
ContextCompat.getColor(
view.context,
R.color.foundation_normal_theme
)
)
}
}

@ -10,13 +10,10 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.cardview.widget.CardView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.component_tabstray2.*
import kotlinx.android.synthetic.main.component_tabstray2.view.*
import kotlinx.android.synthetic.main.tabs_tray_tab_counter2.*
@ -26,7 +23,6 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.home.HomeScreenViewModel
@ -38,13 +34,6 @@ import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsInteractor
class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
private lateinit var navigationInteractor: NavigationInteractor
private val tabLayout: TabLayout? get() =
view?.tab_layout
private val isPrivateModeSelected: Boolean get() =
tabLayout?.selectedTabPosition == TrayPagerAdapter.POSITION_PRIVATE_TABS
private lateinit var tabsTrayStore: TabsTrayStore
private lateinit var browserTrayInteractor: BrowserTrayInteractor
private lateinit var behavior: BottomSheetBehavior<ConstraintLayout>
@ -85,19 +74,9 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
val containerView = inflater.inflate(R.layout.fragment_tab_tray_dialog, container, false)
val view: View = LayoutInflater.from(containerView.context)
.inflate(R.layout.component_tabstray2, containerView as ViewGroup, true)
val activity = activity as HomeActivity
behavior = BottomSheetBehavior.from(view.tab_wrapper)
navigationInteractor =
DefaultNavigationInteractor(
browserStore = activity.components.core.store,
navController = findNavController(),
metrics = activity.components.analytics.metrics,
dismissTabTray = ::dismissAllowingStateLoss,
dismissTabTrayAndNavigateHome = ::dismissTabTrayAndNavigateHome
)
tabsTrayStore = StoreProvider.get(this) { TabsTrayStore() }
return containerView
@ -106,7 +85,6 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
@ExperimentalCoroutinesApi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupMenu(view)
browserTrayInteractor = DefaultBrowserTrayInteractor(
tabsTrayStore,
@ -116,12 +94,22 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
this
)
val navigationInteractor =
DefaultNavigationInteractor(
browserStore = requireComponents.core.store,
navController = findNavController(),
metrics = requireComponents.analytics.metrics,
dismissTabTray = ::dismissAllowingStateLoss,
dismissTabTrayAndNavigateHome = ::dismissTabTrayAndNavigateHome
)
val syncedTabsTrayInteractor = SyncedTabsInteractor(
requireComponents.analytics.metrics,
requireActivity() as HomeActivity,
this
)
setupMenu(view, navigationInteractor)
setupPager(
view.context,
tabsTrayStore,
@ -195,40 +183,23 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor {
}
}
private fun setupMenu(view: View) {
private fun setupMenu(view: View, navigationInteractor: NavigationInteractor) {
view.tab_tray_overflow.setOnClickListener { anchor ->
val tabTrayItemMenu =
TabsTrayMenu(
context = view.context,
browserStore = requireComponents.core.store,
tabLayout = tab_layout
) {
when (it) {
is TabsTrayMenu.Item.ShareAllTabs ->
navigationInteractor.onShareTabsOfTypeClicked(isPrivateModeSelected)
is TabsTrayMenu.Item.OpenTabSettings ->
navigationInteractor.onTabSettingsClicked()
is TabsTrayMenu.Item.CloseAllTabs ->
navigationInteractor.onCloseAllTabsClicked(isPrivateModeSelected)
is TabsTrayMenu.Item.OpenRecentlyClosed ->
navigationInteractor.onOpenRecentlyClosedClicked()
is TabsTrayMenu.Item.SelectTabs ->
{ /* TODO implement when mulitiselect call is available */ }
}
}
requireComponents.analytics.metrics.track(Event.TabsTrayMenuOpened)
val menu = tabTrayItemMenu.menuBuilder.build(view.context)
menu.show(anchor).also { popupMenu ->
(popupMenu.contentView as? CardView)?.setCardBackgroundColor(
ContextCompat.getColor(
view.context,
R.color.foundation_normal_theme
)
)
}
val menu = MenuIntegration(
context = requireContext(),
browserStore = requireComponents.core.store,
tabsTrayStore = TabsTrayStore(),
tabLayout = tab_layout,
navigationInteractor = navigationInteractor
).build()
menu.showWithTheme(anchor)
}
}
private val homeViewModel: HomeScreenViewModel by activityViewModels()
private fun dismissTabTrayAndNavigateHome(sessionId: String) {

@ -6,6 +6,7 @@ package org.mozilla.fenix.tabstray
import mozilla.components.concept.tabstray.Tab
import mozilla.components.lib.state.Action
import mozilla.components.lib.state.Middleware
import mozilla.components.lib.state.State
import mozilla.components.lib.state.Store
@ -147,8 +148,10 @@ internal object TabsTrayReducer {
* dispatched to the store.
*/
class TabsTrayStore(
initialState: TabsTrayState = TabsTrayState()
initialState: TabsTrayState = TabsTrayState(),
middlewares: List<Middleware<TabsTrayState, TabsTrayAction>> = emptyList()
) : Store<TabsTrayState, TabsTrayAction>(
initialState,
TabsTrayReducer::reduce
TabsTrayReducer::reduce,
middlewares
)

@ -0,0 +1,65 @@
/* 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 io.mockk.mockk
import io.mockk.verify
import mozilla.components.support.test.middleware.CaptureActionsMiddleware
import org.junit.Assert.assertNotNull
import org.junit.Ignore
import org.junit.Test
class MenuIntegrationTest {
private val captureMiddleware = CaptureActionsMiddleware<TabsTrayState, TabsTrayAction>()
private val tabsTrayStore = TabsTrayStore(middlewares = listOf(captureMiddleware))
private val interactor = mockk<NavigationInteractor>(relaxed = true)
@Test
fun `WHEN the share all menu item is clicked THEN invoke the action`() {
val menu = MenuIntegration(mockk(), mockk(), tabsTrayStore, mockk(), interactor)
menu.handleMenuClicked(TabsTrayMenu.Item.ShareAllTabs)
verify { interactor.onShareTabsOfTypeClicked(false) }
}
@Test
fun `WHEN the open settings menu item is clicked THEN invoke the action`() {
val menu = MenuIntegration(mockk(), mockk(), tabsTrayStore, mockk(), interactor)
menu.handleMenuClicked(TabsTrayMenu.Item.OpenTabSettings)
verify { interactor.onTabSettingsClicked() }
}
@Test
fun `WHEN the close all menu item is clicked THEN invoke the action`() {
val menu = MenuIntegration(mockk(), mockk(), tabsTrayStore, mockk(), interactor)
menu.handleMenuClicked(TabsTrayMenu.Item.CloseAllTabs)
verify { interactor.onCloseAllTabsClicked(false) }
}
@Test
fun `WHEN the recently menu item is clicked THEN invoke the action`() {
val menu = MenuIntegration(mockk(), mockk(), tabsTrayStore, mockk(), interactor)
menu.handleMenuClicked(TabsTrayMenu.Item.OpenRecentlyClosed)
verify { interactor.onOpenRecentlyClosedClicked() }
}
@Ignore("Enable after we connect this menu item to the store")
@Test
fun `WHEN the select menu item is clicked THEN invoke the action`() {
val menu = MenuIntegration(mockk(), mockk(), tabsTrayStore, mockk(), interactor)
menu.handleMenuClicked(TabsTrayMenu.Item.ShareAllTabs)
assertNotNull(captureMiddleware.findLastAction(TabsTrayAction.EnterSelectMode::class))
}
}
Loading…
Cancel
Save