For #17917: Use View binding in tabs tray

upstream-sync
codrut.topliceanu 3 years ago committed by mergify[bot]
parent 69fa9abdd2
commit bf5b4a5655

@ -9,15 +9,16 @@ import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import androidx.annotation.VisibleForTesting
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.sync_tabs_error_row.view.*
import kotlinx.android.synthetic.main.sync_tabs_list_item.view.*
import kotlinx.android.synthetic.main.view_synced_tabs_group.view.*
import kotlinx.android.synthetic.main.view_synced_tabs_title.view.*
import mozilla.components.browser.toolbar.MAX_URI_LENGTH
import mozilla.components.feature.syncedtabs.view.SyncedTabsView
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.SyncTabsErrorRowBinding
import org.mozilla.fenix.databinding.SyncTabsListItemBinding
import org.mozilla.fenix.databinding.ViewSyncedTabsGroupBinding
import org.mozilla.fenix.databinding.ViewSyncedTabsTitleBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.toShortUrl
import org.mozilla.fenix.sync.SyncedTabsAdapter.AdapterItem
@ -42,8 +43,9 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
private fun bindTab(tab: AdapterItem.Tab) {
val active = tab.tab.active()
itemView.synced_tab_item_title.text = active.title
itemView.synced_tab_item_url.text = active.url
val binding = SyncTabsListItemBinding.bind(itemView)
binding.syncedTabItemTitle.text = active.title
binding.syncedTabItemUrl.text = active.url
.toShortUrl(itemView.context.components.publicSuffixList)
.take(MAX_URI_LENGTH)
}
@ -57,14 +59,15 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
override fun <T : AdapterItem> bind(item: T, interactor: SyncedTabsView.Listener) {
val errorItem = item as AdapterItem.Error
val binding = SyncTabsErrorRowBinding.bind(itemView)
itemView.sync_tabs_error_description.text =
binding.syncTabsErrorDescription.text =
itemView.context.getString(errorItem.descriptionResId)
itemView.sync_tabs_error_cta_button.visibility = GONE
binding.syncTabsErrorCtaButton.visibility = GONE
errorItem.navController?.let { navController ->
itemView.sync_tabs_error_cta_button.visibility = VISIBLE
itemView.sync_tabs_error_cta_button.setOnClickListener {
binding.syncTabsErrorCtaButton.visibility = VISIBLE
binding.syncTabsErrorCtaButton.setOnClickListener {
navController.navigate(NavGraphDirections.actionGlobalTurnOnSync())
}
}
@ -77,12 +80,15 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
class DeviceViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) {
@VisibleForTesting
internal val binding = ViewSyncedTabsGroupBinding.bind(itemView)
override fun <T : AdapterItem> bind(item: T, interactor: SyncedTabsView.Listener) {
bindHeader(item as AdapterItem.Device)
}
private fun bindHeader(device: AdapterItem.Device) {
itemView.synced_tabs_group_name.text = device.device.displayName
binding.syncedTabsGroupName.text = device.device.displayName
}
companion object {
@ -101,7 +107,8 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
class TitleViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) {
override fun <T : AdapterItem> bind(item: T, interactor: SyncedTabsView.Listener) {
itemView.refresh_icon.setOnClickListener { v ->
val binding = ViewSyncedTabsTitleBinding.bind(itemView)
binding.refreshIcon.setOnClickListener { v ->
val rotation = AnimationUtils.loadAnimation(
itemView.context,
R.anim.full_rotation

@ -21,12 +21,6 @@ import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
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.component_tabstray_fab.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.*
import kotlinx.android.synthetic.main.tabs_tray_tab_counter2.*
import kotlinx.android.synthetic.main.tabstray_multiselect_items.*
import kotlinx.coroutines.Dispatchers
import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.state.selector.normalTabs
@ -40,6 +34,11 @@ import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.share.ShareFragment
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.databinding.ComponentTabstray2Binding
import org.mozilla.fenix.databinding.ComponentTabstrayFabBinding
import org.mozilla.fenix.databinding.FragmentTabTrayDialogBinding
import org.mozilla.fenix.databinding.TabsTrayTabCounter2Binding
import org.mozilla.fenix.databinding.TabstrayMultiselectItemsBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
@ -60,7 +59,6 @@ import kotlin.math.max
@Suppress("TooManyFunctions", "LargeClass")
class TabsTrayFragment : AppCompatDialogFragment() {
private var fabView: View? = null
@VisibleForTesting internal lateinit var tabsTrayStore: TabsTrayStore
private lateinit var browserTrayInteractor: BrowserTrayInteractor
private lateinit var tabsTrayInteractor: TabsTrayInteractor
@ -75,6 +73,16 @@ class TabsTrayFragment : AppCompatDialogFragment() {
private val tabsTrayCtaBinding = ViewBoundFeatureWrapper<TabsTrayInfoBannerBinding>()
private val secureTabsTrayBinding = ViewBoundFeatureWrapper<SecureTabsTrayBinding>()
@VisibleForTesting @Suppress("VariableNaming")
internal var _tabsTrayBinding: ComponentTabstray2Binding? = null
private val tabsTrayBinding get() = _tabsTrayBinding!!
@VisibleForTesting @Suppress("VariableNaming")
internal var _tabsTrayDialogBinding: FragmentTabTrayDialogBinding? = null
private val tabsTrayDialogBinding get() = _tabsTrayDialogBinding!!
@VisibleForTesting @Suppress("VariableNaming")
internal var _fabButtonBinding: ComponentTabstrayFabBinding? = null
private val fabButtonBinding get() = _fabButtonBinding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.TabTrayDialogStyle)
@ -88,8 +96,21 @@ class TabsTrayFragment : AppCompatDialogFragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val containerView = inflater.inflate(R.layout.fragment_tab_tray_dialog, container, false)
inflater.inflate(R.layout.component_tabstray2, containerView as ViewGroup, true)
_tabsTrayDialogBinding = FragmentTabTrayDialogBinding.inflate(
inflater,
container,
false
)
_tabsTrayBinding = ComponentTabstray2Binding.inflate(
inflater,
tabsTrayDialogBinding.root,
true
)
_fabButtonBinding = ComponentTabstrayFabBinding.inflate(
LayoutInflater.from(tabsTrayDialogBinding.root.context),
tabsTrayDialogBinding.root,
true
)
val args by navArgs<TabsTrayFragmentArgs>()
val initialMode = if (args.enterMultiselect) {
@ -106,10 +127,14 @@ class TabsTrayFragment : AppCompatDialogFragment() {
)
}
fabView = LayoutInflater.from(containerView.context)
.inflate(R.layout.component_tabstray_fab, containerView, true)
return tabsTrayDialogBinding.root
}
return containerView
override fun onDestroyView() {
super.onDestroyView()
_tabsTrayBinding = null
_tabsTrayDialogBinding = null
_fabButtonBinding = null
}
@Suppress("LongMethod")
@ -118,7 +143,8 @@ class TabsTrayFragment : AppCompatDialogFragment() {
val activity = activity as HomeActivity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
new_tab_button.accessibilityTraversalAfter = tab_layout.id
fabButtonBinding.newTabButton.accessibilityTraversalAfter =
tabsTrayBinding.tabLayout.id
}
requireComponents.analytics.metrics.track(Event.TabsTrayOpened)
@ -165,7 +191,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
requireComponents.analytics.metrics
)
setupMenu(view, navigationInteractor)
setupMenu(navigationInteractor)
setupPager(
view.context,
tabsTrayStore,
@ -180,7 +206,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
}
trayBehaviorManager = TabSheetBehaviorManager(
behavior = BottomSheetBehavior.from(view.tab_wrapper),
behavior = BottomSheetBehavior.from(tabsTrayBinding.tabWrapper),
orientation = resources.configuration.orientation,
maxNumberOfTabs = max(
requireContext().components.core.store.state.normalTabs.size,
@ -199,7 +225,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
feature = TabsTrayInfoBannerBinding(
context = view.context,
store = requireComponents.core.store,
infoBannerView = view.info_banner,
infoBannerView = tabsTrayBinding.infoBanner,
settings = requireComponents.settings,
navigationInteractor = navigationInteractor
),
@ -209,7 +235,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
tabLayoutMediator.set(
feature = TabLayoutMediator(
tabLayout = tab_layout,
tabLayout = tabsTrayBinding.tabLayout,
interactor = tabsTrayInteractor,
browsingModeManager = activity.browsingModeManager,
tabsTrayStore = tabsTrayStore,
@ -219,10 +245,14 @@ class TabsTrayFragment : AppCompatDialogFragment() {
view = view
)
val tabsTrayTabCounter2Binding = TabsTrayTabCounter2Binding.bind(
tabsTrayBinding.tabLayout
)
tabCounterBinding.set(
feature = TabCounterBinding(
store = requireComponents.core.store,
counter = tab_counter
counter = tabsTrayTabCounter2Binding.tabCounter
),
owner = this,
view = view
@ -231,32 +261,37 @@ class TabsTrayFragment : AppCompatDialogFragment() {
floatingActionButtonBinding.set(
feature = FloatingActionButtonBinding(
store = tabsTrayStore,
actionButton = new_tab_button,
actionButton = fabButtonBinding.newTabButton,
browserTrayInteractor = browserTrayInteractor
),
owner = this,
view = view
)
val tabsTrayMultiselectItemsBinding = TabstrayMultiselectItemsBinding.bind(
tabsTrayBinding.root
)
selectionBannerBinding.set(
feature = SelectionBannerBinding(
context = requireContext(),
binding = tabsTrayBinding,
store = tabsTrayStore,
navInteractor = navigationInteractor,
tabsTrayInteractor = tabsTrayInteractor,
containerView = view,
backgroundView = topBar,
backgroundView = tabsTrayBinding.topBar,
showOnSelectViews = VisibilityModifier(
collect_multi_select,
share_multi_select,
menu_multi_select,
multiselect_title,
exit_multi_select
tabsTrayMultiselectItemsBinding.collectMultiSelect,
tabsTrayMultiselectItemsBinding.shareMultiSelect,
tabsTrayMultiselectItemsBinding.menuMultiSelect,
tabsTrayBinding.multiselectTitle,
tabsTrayBinding.exitMultiSelect
),
showOnNormalViews = VisibilityModifier(
tab_layout,
tab_tray_overflow,
new_tab_button
tabsTrayBinding.tabLayout,
tabsTrayBinding.tabTrayOverflow,
fabButtonBinding.newTabButton
)
),
owner = this,
@ -266,8 +301,8 @@ class TabsTrayFragment : AppCompatDialogFragment() {
selectionHandleBinding.set(
feature = SelectionHandleBinding(
store = tabsTrayStore,
handle = handle,
containerLayout = tab_wrapper
handle = tabsTrayBinding.handle,
containerLayout = tabsTrayBinding.tabWrapper
),
owner = this,
view = view
@ -295,7 +330,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
trayBehaviorManager.updateDependingOnOrientation(newConfig.orientation)
if (requireContext().settings().gridTabView) {
tabsTray.adapter?.notifyDataSetChanged()
tabsTrayBinding.tabsTray.adapter?.notifyDataSetChanged()
}
}
@ -321,7 +356,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
},
operation = { },
elevation = ELEVATION,
anchorView = if (new_tab_button.isVisible) new_tab_button else null
anchorView = if (fabButtonBinding.newTabButton.isVisible) fabButtonBinding.newTabButton else null
)
}
@ -333,7 +368,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
browserInteractor: BrowserTrayInteractor,
navigationInteractor: NavigationInteractor
) {
tabsTray.apply {
tabsTrayBinding.tabsTray.apply {
adapter = TrayPagerAdapter(
context,
store,
@ -347,8 +382,8 @@ class TabsTrayFragment : AppCompatDialogFragment() {
}
@VisibleForTesting
internal fun setupMenu(view: View, navigationInteractor: NavigationInteractor) {
view.tab_tray_overflow.setOnClickListener { anchor ->
internal fun setupMenu(navigationInteractor: NavigationInteractor) {
tabsTrayBinding.tabTrayOverflow.setOnClickListener { anchor ->
requireComponents.analytics.metrics.track(Event.TabsTrayMenuOpened)
@ -356,7 +391,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
context = requireContext(),
browserStore = requireComponents.core.store,
tabsTrayStore = tabsTrayStore,
tabLayout = tab_layout,
tabLayout = tabsTrayBinding.tabLayout,
navigationInteractor = navigationInteractor
).build()
@ -375,8 +410,8 @@ class TabsTrayFragment : AppCompatDialogFragment() {
@VisibleForTesting
internal fun setupBackgroundDismissalListener(block: (View) -> Unit) {
tabLayout.setOnClickListener(block)
handle.setOnClickListener(block)
tabsTrayDialogBinding.tabLayout.setOnClickListener(block)
tabsTrayBinding.handle.setOnClickListener(block)
}
@VisibleForTesting
@ -396,8 +431,8 @@ class TabsTrayFragment : AppCompatDialogFragment() {
@VisibleForTesting
internal fun selectTabPosition(position: Int, smoothScroll: Boolean) {
tabsTray.setCurrentItem(position, smoothScroll)
tab_layout.getTabAt(position)?.select()
tabsTrayBinding.tabsTray.setCurrentItem(position, smoothScroll)
tabsTrayBinding.tabLayout.getTabAt(position)?.select()
}
@VisibleForTesting
@ -447,7 +482,7 @@ class TabsTrayFragment : AppCompatDialogFragment() {
return if (requireComponents.settings.accessibilityServicesEnabled) {
null
} else {
new_tab_button
fabButtonBinding.newTabButton
}
}

@ -13,7 +13,6 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.AppCompatImageButton
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.checkbox_item.view.*
import mozilla.components.browser.state.selector.findTabOrCustomTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.tabstray.TabViewHolder
@ -102,8 +101,8 @@ abstract class AbstractBrowserTabViewHolder(
}
}
fun showTabIsMultiSelectEnabled(isSelected: Boolean) {
itemView.selected_mask.isVisible = isSelected
fun showTabIsMultiSelectEnabled(selectedMaskView: View?, isSelected: Boolean) {
selectedMaskView?.isVisible = isSelected
closeView.isInvisible = trayStore.state.mode is TabsTrayState.Mode.Select
}

@ -13,9 +13,9 @@ import mozilla.components.concept.tabstray.Tab
import mozilla.components.concept.tabstray.TabsTray
import mozilla.components.support.base.observer.Observable
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.TabTrayGridItemBinding
import org.mozilla.fenix.ext.increaseTapArea
import kotlin.math.max
import kotlinx.android.synthetic.main.tab_tray_grid_item.view.tab_tray_grid_item
import org.mozilla.fenix.selection.SelectionHolder
import org.mozilla.fenix.tabstray.TabsTrayStore
@ -39,7 +39,8 @@ class BrowserTabGridViewHolder(
)
override fun updateSelectedTabIndicator(showAsSelected: Boolean) {
itemView.tab_tray_grid_item.background = if (showAsSelected) {
val binding = TabTrayGridItemBinding.bind(itemView)
binding.tabTrayGridItem.background = if (showAsSelected) {
AppCompatResources.getDrawable(itemView.context, R.drawable.tab_tray_grid_item_selected_border)
} else {
null

@ -6,9 +6,9 @@ package org.mozilla.fenix.tabstray.browser
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.tab_tray_item.view.*
import mozilla.components.browser.tabstray.TabsAdapter.Companion.PAYLOAD_DONT_HIGHLIGHT_SELECTED_ITEM
import mozilla.components.browser.tabstray.TabsAdapter.Companion.PAYLOAD_HIGHLIGHT_SELECTED_ITEM
import mozilla.components.browser.thumbnails.loader.ThumbnailLoader
@ -17,6 +17,8 @@ import mozilla.components.concept.tabstray.TabsTray
import mozilla.components.support.base.observer.Observable
import mozilla.components.support.base.observer.ObserverRegistry
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.TabTrayGridItemBinding
import org.mozilla.fenix.databinding.TabTrayItemBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.selection.SelectionHolder
import org.mozilla.fenix.tabstray.TabsTrayStore
@ -68,14 +70,23 @@ class BrowserTabsAdapter(
override fun onBindViewHolder(holder: AbstractBrowserTabViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
var selectedMaskView: View? = null
holder.tab?.let { tab ->
holder.itemView.mozac_browser_tabstray_close.setOnClickListener {
interactor.close(tab)
when (getItemViewType(position)) {
ViewType.GRID.layoutRes -> {
val gridBinding = TabTrayGridItemBinding.bind(holder.itemView)
selectedMaskView = gridBinding.checkboxInclude.selectedMask
gridBinding.mozacBrowserTabstrayClose.setOnClickListener { interactor.close(tab) }
}
ViewType.LIST.layoutRes -> {
val listBinding = TabTrayItemBinding.bind(holder.itemView)
selectedMaskView = listBinding.checkboxInclude.selectedMask
listBinding.mozacBrowserTabstrayClose.setOnClickListener { interactor.close(tab) }
}
}
selectionHolder?.let {
holder.showTabIsMultiSelectEnabled(it.selectedItems.contains(tab))
holder.showTabIsMultiSelectEnabled(selectedMaskView, it.selectedItems.contains(tab))
}
}
}
@ -103,7 +114,18 @@ class BrowserTabsAdapter(
}
selectionHolder?.let {
holder.showTabIsMultiSelectEnabled(it.selectedItems.contains(holder.tab))
var selectedMaskView: View? = null
when (getItemViewType(position)) {
ViewType.GRID.layoutRes -> {
val gridBinding = TabTrayGridItemBinding.bind(holder.itemView)
selectedMaskView = gridBinding.checkboxInclude.selectedMask
}
ViewType.LIST.layoutRes -> {
val listBinding = TabTrayItemBinding.bind(holder.itemView)
selectedMaskView = listBinding.checkboxInclude.selectedMask
}
}
holder.showTabIsMultiSelectEnabled(selectedMaskView, it.selectedItems.contains(holder.tab))
}
}

@ -9,9 +9,6 @@ import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.component_tabstray2.view.exit_multi_select
import kotlinx.android.synthetic.main.component_tabstray2.view.multiselect_title
import kotlinx.android.synthetic.main.tabstray_multiselect_items.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
@ -19,6 +16,8 @@ import kotlinx.coroutines.flow.map
import mozilla.components.lib.state.helpers.AbstractBinding
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.ComponentTabstray2Binding
import org.mozilla.fenix.databinding.TabstrayMultiselectItemsBinding
import org.mozilla.fenix.tabstray.NavigationInteractor
import org.mozilla.fenix.tabstray.TabsTrayInteractor
import org.mozilla.fenix.tabstray.TabsTrayState
@ -45,6 +44,7 @@ import org.mozilla.fenix.tabstray.ext.showWithTheme
@Suppress("LongParameterList")
class SelectionBannerBinding(
private val context: Context,
private val binding: ComponentTabstray2Binding,
private val store: TabsTrayStore,
private val navInteractor: NavigationInteractor,
private val tabsTrayInteractor: TabsTrayInteractor,
@ -64,7 +64,7 @@ class SelectionBannerBinding(
override fun start() {
super.start()
initListeners(containerView)
initListeners()
}
override suspend fun onState(flow: Flow<TabsTrayState>) {
@ -89,20 +89,22 @@ class SelectionBannerBinding(
}
}
private fun initListeners(containerView: View) {
containerView.share_multi_select.setOnClickListener {
private fun initListeners() {
val tabsTrayMultiselectItemsBinding = TabstrayMultiselectItemsBinding.bind(binding.root)
tabsTrayMultiselectItemsBinding.shareMultiSelect.setOnClickListener {
navInteractor.onShareTabs(store.state.mode.selectedTabs)
}
containerView.collect_multi_select.setOnClickListener {
tabsTrayMultiselectItemsBinding.collectMultiSelect.setOnClickListener {
navInteractor.onSaveToCollections(store.state.mode.selectedTabs)
}
containerView.exit_multi_select.setOnClickListener {
binding.exitMultiSelect.setOnClickListener {
store.dispatch(ExitSelectMode)
}
containerView.menu_multi_select.setOnClickListener { anchor ->
tabsTrayMultiselectItemsBinding.menuMultiSelect.setOnClickListener { anchor ->
val menu = SelectionMenuIntegration(
context,
store,
@ -133,9 +135,9 @@ class SelectionBannerBinding(
@VisibleForTesting
private fun updateSelectTitle(selectedMode: Boolean, tabCount: Int) {
if (selectedMode) {
containerView.multiselect_title.text =
binding.multiselectTitle.text =
context.getString(R.string.tab_tray_multi_select_title, tabCount)
containerView.multiselect_title.importantForAccessibility =
binding.multiselectTitle.importantForAccessibility =
View.IMPORTANT_FOR_ACCESSIBILITY_YES
}
}

@ -10,7 +10,6 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.findFragment
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.component_sync_tabs_tray_layout.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
@ -20,6 +19,7 @@ import mozilla.components.feature.syncedtabs.SyncedTabsFeature
import mozilla.components.feature.syncedtabs.view.SyncedTabsView
import mozilla.components.support.base.observer.Observable
import mozilla.components.support.base.observer.ObserverRegistry
import org.mozilla.fenix.databinding.ComponentSyncTabsTrayLayoutBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.sync.SyncedTabsAdapter
import org.mozilla.fenix.sync.SyncedTabsTitleDecoration
@ -40,6 +40,8 @@ class SyncedTabsTrayLayout @JvmOverloads constructor(
private val lifecycleProvider = LifecycleViewProvider(this)
private val coroutineScope = CoroutineScope(Dispatchers.Main)
private var _binding: ComponentSyncTabsTrayLayoutBinding? = null
private val binding get() = _binding!!
private val syncedTabsFeature by lazy {
SyncedTabsFeature(
@ -67,14 +69,15 @@ class SyncedTabsTrayLayout @JvmOverloads constructor(
override var listener: SyncedTabsView.Listener? = null
override fun onFinishInflate() {
synced_tabs_list.addItemDecoration(SyncedTabsTitleDecoration(context))
_binding = ComponentSyncTabsTrayLayoutBinding.bind(this)
binding.syncedTabsList.addItemDecoration(SyncedTabsTitleDecoration(context))
super.onFinishInflate()
}
override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) {
coroutineScope.launch {
(synced_tabs_list.adapter as SyncedTabsAdapter).updateData(syncedTabs)
(binding.syncedTabsList.adapter as SyncedTabsAdapter).updateData(syncedTabs)
}
}
@ -93,7 +96,7 @@ class SyncedTabsTrayLayout @JvmOverloads constructor(
val errorItem = error.toAdapterItem(descriptionResId, navController)
val errorList: List<SyncedTabsAdapter.AdapterItem> = listOf(errorItem)
(synced_tabs_list.adapter as SyncedTabsAdapter).submitList(errorList)
(binding.syncedTabsList.adapter as SyncedTabsAdapter).submitList(errorList)
}
}
@ -106,6 +109,7 @@ class SyncedTabsTrayLayout @JvmOverloads constructor(
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
_binding = null
syncedTabsFeature.stop()
syncButtonBinding.stop()

@ -89,21 +89,18 @@
app:tabRippleColor="@android:color/transparent">
<com.google.android.material.tabs.TabItem
android:id="@+id/default_tab_item"
android:layout_width="0dp"
android:layout_height="match_parent"
android:contentDescription="@string/tab_header_label"
android:layout="@layout/tabs_tray_tab_counter2" />
<com.google.android.material.tabs.TabItem
android:id="@+id/private_tab_item"
android:layout_width="0dp"
android:layout_height="match_parent"
android:contentDescription="@string/tabs_header_private_tabs_title"
android:icon="@drawable/ic_private_browsing" />
<com.google.android.material.tabs.TabItem
android:id="@+id/synced_tab_item"
android:layout_width="0dp"
android:layout_height="match_parent"
android:contentDescription="@string/tabs_header_synced_tabs_title"

@ -112,7 +112,9 @@ A FrameLayout here is an efficient way of having a views stack while allowing:
android:layout_height="match_parent"
android:contentDescription="@string/mozac_browser_tabstray_open_tab" />
<include layout="@layout/checkbox_item" />
<include
android:id="@+id/checkbox_include"
layout="@layout/checkbox_item" />
</androidx.cardview.widget.CardView>

@ -53,7 +53,9 @@
android:layout_height="match_parent"
android:contentDescription="@string/mozac_browser_tabstray_open_tab" />
<include layout="@layout/checkbox_item" />
<include
android:id="@+id/checkbox_include"
layout="@layout/checkbox_item" />
</androidx.cardview.widget.CardView>

@ -10,9 +10,8 @@ import android.widget.TextView
import io.mockk.Called
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import kotlinx.android.synthetic.main.sync_tabs_list_item.view.*
import kotlinx.android.synthetic.main.view_synced_tabs_group.view.*
import mozilla.components.browser.storage.sync.Tab
import mozilla.components.browser.storage.sync.TabEntry
import mozilla.components.concept.sync.Device
@ -24,6 +23,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.SyncTabsListItemBinding
import org.mozilla.fenix.databinding.ViewSyncedTabsGroupBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
@ -39,6 +40,8 @@ class SyncedTabsViewHolderTest {
private lateinit var noTabsView: View
private lateinit var noTabsViewHolder: SyncedTabsViewHolder.NoTabsViewHolder
private lateinit var syncTabsListItemBinding: SyncTabsListItemBinding
private val tab = Tab(
history = listOf(
mockk(),
@ -60,11 +63,13 @@ class SyncedTabsViewHolderTest {
tabView = inflater.inflate(SyncedTabsViewHolder.TabViewHolder.LAYOUT_ID, null)
tabViewHolder = SyncedTabsViewHolder.TabViewHolder(tabView)
deviceViewGroupName = mockk(relaxUnitFun = true)
deviceView = mockk {
every { synced_tabs_group_name } returns deviceViewGroupName
}
deviceViewHolder = SyncedTabsViewHolder.DeviceViewHolder(deviceView)
syncTabsListItemBinding = SyncTabsListItemBinding.bind(tabView)
val viewSyncedTabsGroupBinding = ViewSyncedTabsGroupBinding.inflate(inflater)
deviceView = mockk()
deviceViewHolder = SyncedTabsViewHolder.DeviceViewHolder(spyk(viewSyncedTabsGroupBinding.root))
deviceViewGroupName = spyk(viewSyncedTabsGroupBinding.syncedTabsGroupName)
titleView = inflater.inflate(SyncedTabsViewHolder.TitleViewHolder.LAYOUT_ID, null)
titleViewHolder = SyncedTabsViewHolder.TitleViewHolder(titleView)
@ -77,8 +82,8 @@ class SyncedTabsViewHolderTest {
fun `TabViewHolder binds active tab`() {
tabViewHolder.bind(SyncedTabsAdapter.AdapterItem.Tab(tab), mockk())
assertEquals("Firefox", tabView.synced_tab_item_title.text)
assertEquals("mozilla.org", tabView.synced_tab_item_url.text)
assertEquals("Firefox", syncTabsListItemBinding.syncedTabItemTitle.text)
assertEquals("mozilla.org", syncTabsListItemBinding.syncedTabItemUrl.text)
}
@Test
@ -98,7 +103,7 @@ class SyncedTabsViewHolderTest {
}
deviceViewHolder.bind(SyncedTabsAdapter.AdapterItem.Device(device), mockk())
verify { deviceViewGroupName.text = "Charcoal" }
assertEquals("Charcoal", deviceViewHolder.binding.syncedTabsGroupName.text)
}
@Test
@ -109,7 +114,7 @@ class SyncedTabsViewHolderTest {
}
deviceViewHolder.bind(SyncedTabsAdapter.AdapterItem.Device(device), mockk())
verify { deviceViewGroupName.text = "Emerald" }
assertEquals("Emerald", deviceViewHolder.binding.syncedTabsGroupName.text)
}
@Test

@ -8,37 +8,33 @@ import android.content.Context
import android.content.res.Configuration
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.ImageButton
import android.view.ViewGroup
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import androidx.viewbinding.ViewBindings
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.tabs.TabLayout
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.slot
import io.mockk.spyk
import io.mockk.unmockkStatic
import io.mockk.verify
import kotlinx.android.synthetic.main.component_tabstray2.*
import kotlinx.android.synthetic.main.component_tabstray2.view.*
import kotlinx.android.synthetic.main.component_tabstray_fab.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.*
import kotlinx.coroutines.CoroutineScope
import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertSame
import org.junit.Before
import org.junit.Test
@ -47,6 +43,9 @@ import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.databinding.ComponentTabstray2Binding
import org.mozilla.fenix.databinding.ComponentTabstrayFabBinding
import org.mozilla.fenix.databinding.FragmentTabTrayDialogBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -58,15 +57,25 @@ import org.mozilla.fenix.utils.allowUndo
@RunWith(FenixRobolectricTestRunner::class)
class TabsTrayFragmentTest {
private lateinit var context: Context
private lateinit var view: View
private lateinit var view: ViewGroup
private lateinit var fragment: TabsTrayFragment
private lateinit var tabsTrayBinding: ComponentTabstray2Binding
private lateinit var tabsTrayDialogBinding: FragmentTabTrayDialogBinding
private lateinit var fabButtonBinding: ComponentTabstrayFabBinding
@Before
fun setup() {
context = mockk(relaxed = true)
view = mockk(relaxed = true)
val inflater = LayoutInflater.from(testContext)
tabsTrayDialogBinding = FragmentTabTrayDialogBinding.inflate(inflater)
tabsTrayBinding = ComponentTabstray2Binding.inflate(inflater)
fabButtonBinding = ComponentTabstrayFabBinding.inflate(inflater)
fragment = spyk(TabsTrayFragment())
fragment._tabsTrayBinding = tabsTrayBinding
fragment._tabsTrayDialogBinding = tabsTrayDialogBinding
fragment._fabButtonBinding = fabButtonBinding
every { fragment.context } returns context
every { fragment.view } returns view
}
@ -78,10 +87,7 @@ class TabsTrayFragmentTest {
mockkStatic("androidx.lifecycle.LifecycleOwnerKt")
val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true)
every { any<LifecycleOwner>().lifecycleScope } returns lifecycleScope
val newTabButton: ExtendedFloatingActionButton = mockk {
every { visibility } returns View.VISIBLE
}
every { fragment.new_tab_button } returns newTabButton
fabButtonBinding.newTabButton.isVisible = true
every { fragment.context } returns testContext // needed for getString()
every { any<CoroutineScope>().allowUndo(any(), any(), any(), any(), any(), any(), any(), any()) } just Runs
@ -89,12 +95,12 @@ class TabsTrayFragmentTest {
verify {
lifecycleScope.allowUndo(
fragment.view!!,
view,
testContext.getString(R.string.snackbar_private_tab_closed),
testContext.getString(R.string.snackbar_deleted_undo),
any(),
any(),
newTabButton,
fabButtonBinding.newTabButton,
TabsTrayFragment.ELEVATION,
false
)
@ -112,10 +118,6 @@ class TabsTrayFragmentTest {
mockkStatic("androidx.lifecycle.LifecycleOwnerKt")
val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true)
every { any<LifecycleOwner>().lifecycleScope } returns lifecycleScope
val newTabButton: ExtendedFloatingActionButton = mockk {
every { visibility } returns View.GONE
}
every { fragment.new_tab_button } returns newTabButton
every { fragment.context } returns testContext // needed for getString()
every { any<CoroutineScope>().allowUndo(any(), any(), any(), any(), any(), any(), any(), any()) } just Runs
@ -123,7 +125,7 @@ class TabsTrayFragmentTest {
verify {
lifecycleScope.allowUndo(
fragment.view!!,
view,
testContext.getString(R.string.snackbar_private_tab_closed),
testContext.getString(R.string.snackbar_deleted_undo),
any(),
@ -146,10 +148,7 @@ class TabsTrayFragmentTest {
mockkStatic("androidx.lifecycle.LifecycleOwnerKt")
val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true)
every { any<LifecycleOwner>().lifecycleScope } returns lifecycleScope
val newTabButton: ExtendedFloatingActionButton = mockk {
every { visibility } returns View.VISIBLE
}
every { fragment.new_tab_button } returns newTabButton
fabButtonBinding.newTabButton.isVisible = true
every { fragment.context } returns testContext // needed for getString()
every { any<CoroutineScope>().allowUndo(any(), any(), any(), any(), any(), any(), any(), any()) } just Runs
@ -157,12 +156,12 @@ class TabsTrayFragmentTest {
verify {
lifecycleScope.allowUndo(
fragment.view!!,
view,
testContext.getString(R.string.snackbar_tab_closed),
testContext.getString(R.string.snackbar_deleted_undo),
any(),
any(),
newTabButton,
fabButtonBinding.newTabButton,
TabsTrayFragment.ELEVATION,
false
)
@ -180,10 +179,6 @@ class TabsTrayFragmentTest {
mockkStatic("androidx.lifecycle.LifecycleOwnerKt")
val lifecycleScope: LifecycleCoroutineScope = mockk(relaxed = true)
every { any<LifecycleOwner>().lifecycleScope } returns lifecycleScope
val newTabButton: ExtendedFloatingActionButton = mockk {
every { visibility } returns View.GONE
}
every { fragment.new_tab_button } returns newTabButton
every { fragment.context } returns testContext // needed for getString()
every { any<CoroutineScope>().allowUndo(any(), any(), any(), any(), any(), any(), any(), any()) } just Runs
@ -191,7 +186,7 @@ class TabsTrayFragmentTest {
verify {
lifecycleScope.allowUndo(
fragment.view!!,
view,
testContext.getString(R.string.snackbar_tab_closed),
testContext.getString(R.string.snackbar_deleted_undo),
any(),
@ -209,28 +204,25 @@ class TabsTrayFragmentTest {
@Test
fun `WHEN setupPager is called THEN it sets the tray adapter and disables user initiated scrolling`() {
val tray: ViewPager2 = mockk(relaxed = true)
val store: TabsTrayStore = mockk()
val trayInteractor: TabsTrayInteractor = mockk()
val browserInteractor: BrowserTrayInteractor = mockk()
val navigationInteractor: NavigationInteractor = mockk()
val browserStore: BrowserStore = mockk()
every { fragment.tabsTray } returns tray
every { context.components.core.store } returns browserStore
val adapterSlot = slot<TrayPagerAdapter>()
fragment.setupPager(
context, store, trayInteractor, browserInteractor, navigationInteractor
)
verify { tray.adapter = capture(adapterSlot) }
assertSame(context, adapterSlot.captured.context)
assertSame(store, adapterSlot.captured.store)
assertSame(trayInteractor, adapterSlot.captured.interactor)
assertSame(browserInteractor, adapterSlot.captured.browserInteractor)
assertSame(navigationInteractor, adapterSlot.captured.navInteractor)
assertSame(browserStore, adapterSlot.captured.browserStore)
verify { tray.isUserInputEnabled = false }
val adapter = (tabsTrayBinding.tabsTray.adapter as TrayPagerAdapter)
assertSame(context, adapter.context)
assertSame(store, adapter.store)
assertSame(trayInteractor, adapter.interactor)
assertSame(browserInteractor, adapter.browserInteractor)
assertSame(navigationInteractor, adapter.navInteractor)
assertSame(browserStore, adapter.browserStore)
assertFalse(tabsTrayBinding.tabsTray.isUserInputEnabled)
}
@Test
@ -238,13 +230,10 @@ class TabsTrayFragmentTest {
try {
mockkStatic("org.mozilla.fenix.tabstray.ext.BrowserMenuKt")
val navigationInteractor: NavigationInteractor = mockk()
val threeDotMenu = ImageButton(testContext)
every { view.tab_tray_overflow } returns threeDotMenu
val metrics: MetricController = mockk(relaxed = true)
every { context.components.analytics.metrics } returns metrics
every { context.components.core.store } returns mockk()
every { fragment.tabsTrayStore } returns mockk()
every { fragment.tab_layout } returns mockk<TabLayout>()
val menu: BrowserMenu = mockk {
every { showWithTheme(any()) } just Runs
}
@ -253,12 +242,12 @@ class TabsTrayFragmentTest {
}
every { fragment.getTrayMenu(any(), any(), any(), any(), any()) } returns menuBuilder
fragment.setupMenu(view, navigationInteractor)
threeDotMenu.performClick()
fragment.setupMenu(navigationInteractor)
tabsTrayBinding.tabTrayOverflow.performClick()
verify { metrics.track(Event.TabsTrayMenuOpened) }
verify { menuBuilder.build() }
verify { menu.showWithTheme(threeDotMenu) }
verify { menu.showWithTheme(tabsTrayBinding.tabTrayOverflow) }
} finally {
unmockkStatic("org.mozilla.fenix.tabstray.ext.BrowserMenuKt")
}
@ -284,16 +273,12 @@ class TabsTrayFragmentTest {
fun `WHEN setupBackgroundDismissalListener is called THEN it sets a click listener for tray's tabLayout and handle`() {
var clickCount = 0
val callback: (View) -> Unit = { clickCount++ }
val tabLayout = CoordinatorLayout(testContext)
val handle = Button(testContext)
every { fragment.tabLayout } returns tabLayout
every { fragment.handle } returns handle
fragment.setupBackgroundDismissalListener(callback)
tabLayout.performClick()
tabsTrayDialogBinding.tabLayout.performClick()
assertEquals(1, clickCount)
handle.performClick()
tabsTrayBinding.handle.performClick()
assertEquals(2, clickCount)
}
@ -337,13 +322,19 @@ class TabsTrayFragmentTest {
val tabLayout: TabLayout = mockk {
every { getTabAt(any()) } returns tab
}
every { fragment.tab_layout } returns tabLayout
every { fragment.tabsTray } returns tabsTray
fragment.selectTabPosition(2, true)
mockkStatic(ViewBindings::class) {
every { ViewBindings.findChildViewById<View>(tabsTrayBinding.root, tabsTrayBinding.tabsTray.id) } returns tabsTray
every { ViewBindings.findChildViewById<View>(tabsTrayBinding.root, tabsTrayBinding.tabLayout.id) } returns tabLayout
tabsTrayBinding = ComponentTabstray2Binding.bind(tabsTrayBinding.root)
fragment._tabsTrayBinding = tabsTrayBinding
verify { tabsTray.setCurrentItem(2, true) }
verify { tab.select() }
fragment.selectTabPosition(2, true)
verify { tabsTray.setCurrentItem(2, true) }
verify { tab.select() }
}
}
@Test
@ -371,9 +362,10 @@ class TabsTrayFragmentTest {
@Test
fun `WHEN the tabs tray is declared in XML THEN certain options are set for the behavior`() {
val view: View = LayoutInflater.from(testContext)
.inflate(R.layout.component_tabstray2, CoordinatorLayout(testContext), true)
val behavior = BottomSheetBehavior.from(view.tab_wrapper)
tabsTrayBinding = ComponentTabstray2Binding.inflate(
LayoutInflater.from(testContext), CoordinatorLayout(testContext), true
)
val behavior = BottomSheetBehavior.from(tabsTrayBinding.tabWrapper)
Assert.assertFalse(behavior.isFitToContents)
Assert.assertFalse(behavior.skipCollapsed)
@ -382,55 +374,31 @@ class TabsTrayFragmentTest {
@Test
fun `GIVEN a grid TabView WHEN onConfigurationChanged is called THEN the adapter structure is updated`() {
val tray: ViewPager2 = mockk(relaxed = true)
val store: TabsTrayStore = mockk()
val trayInteractor: TabsTrayInteractor = mockk()
val browserInteractor: BrowserTrayInteractor = mockk()
val navigationInteractor: NavigationInteractor = mockk()
val browserStore: BrowserStore = mockk()
every { fragment.tabsTray } returns tray
every { context.components.core.store } returns browserStore
every { context.settings().gridTabView } returns true
fragment.setupPager(
context, store, trayInteractor, browserInteractor, navigationInteractor
)
val adapter = mockk<TrayPagerAdapter>(relaxed = true)
tabsTrayBinding.tabsTray.adapter = adapter
fragment._tabsTrayBinding = tabsTrayBinding
val trayBehaviorManager: TabSheetBehaviorManager = mockk(relaxed = true)
fragment.trayBehaviorManager = trayBehaviorManager
val newConfiguration = Configuration()
fragment.onConfigurationChanged(newConfiguration)
verify { tray.adapter?.notifyDataSetChanged() }
verify { adapter.notifyDataSetChanged() }
}
@Test
fun `GIVEN a list TabView WHEN onConfigurationChanged is called THEN the adapter structure is NOT updated`() {
val tray: ViewPager2 = mockk(relaxed = true)
val store: TabsTrayStore = mockk()
val trayInteractor: TabsTrayInteractor = mockk()
val browserInteractor: BrowserTrayInteractor = mockk()
val navigationInteractor: NavigationInteractor = mockk()
val browserStore: BrowserStore = mockk()
every { fragment.tabsTray } returns tray
every { context.components.core.store } returns browserStore
every { context.settings().gridTabView } returns false
fragment.setupPager(
context, store, trayInteractor, browserInteractor, navigationInteractor
)
val adapter = mockk<TrayPagerAdapter>(relaxed = true)
tabsTrayBinding.tabsTray.adapter = adapter
fragment._tabsTrayBinding = tabsTrayBinding
val trayBehaviorManager: TabSheetBehaviorManager = mockk(relaxed = true)
fragment.trayBehaviorManager = trayBehaviorManager
val newConfiguration = Configuration()
fragment.onConfigurationChanged(newConfiguration)
verify(exactly = 0) { tray.adapter?.notifyDataSetChanged() }
verify(exactly = 0) { adapter.notifyDataSetChanged() }
}
}

@ -4,8 +4,10 @@
package org.mozilla.fenix.tabstray.browser
import android.view.LayoutInflater
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.tabstray.TabsAdapter.Companion.PAYLOAD_DONT_HIGHLIGHT_SELECTED_ITEM
import mozilla.components.browser.tabstray.TabsAdapter.Companion.PAYLOAD_HIGHLIGHT_SELECTED_ITEM
@ -14,6 +16,7 @@ import mozilla.components.concept.tabstray.Tabs
import mozilla.components.support.test.robolectric.testContext
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.databinding.TabTrayItemBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.selection.SelectionHolder
import org.mozilla.fenix.tabstray.TabsTrayStore
@ -51,10 +54,20 @@ class BrowserTabsAdapterTest {
@Test
fun `WHEN the selection holder is set THEN update the selected tab`() {
val adapter = BrowserTabsAdapter(context, interactor, store)
val holder = mockk<AbstractBrowserTabViewHolder>(relaxed = true)
val binding = TabTrayItemBinding.inflate(LayoutInflater.from(testContext))
val holder = spyk(
BrowserTabListViewHolder(
imageLoader = mockk(),
browserTrayInteractor = interactor,
store = store,
selectionHolder = null,
itemView = binding.root
)
)
val tab = createTab("tab1")
every { holder.tab }.answers { tab }
testSelectionHolder.internalState.add(tab)
adapter.selectionHolder = testSelectionHolder
@ -69,7 +82,7 @@ class BrowserTabsAdapterTest {
adapter.onBindViewHolder(holder, 0, listOf(PAYLOAD_DONT_HIGHLIGHT_SELECTED_ITEM))
verify { holder.showTabIsMultiSelectEnabled(true) }
verify { holder.showTabIsMultiSelectEnabled(any(), true) }
}
private val testSelectionHolder = object : SelectionHolder<Tab> {

Loading…
Cancel
Save