Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

For #21236: Separate tabs with the same search term into a different section #21177

Merged
merged 3 commits into from Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/main/java/org/mozilla/fenix/FeatureFlags.kt
Expand Up @@ -63,4 +63,9 @@ object FeatureFlags {
* Enables customizing the home screen
*/
val customizeHome = Config.channel.isNightlyOrDebug

/**
* Identifies and separates the tabs list with a group containing search term tabs.
*/
val tabGroupFeature = Config.channel.isNightlyOrDebug
}
50 changes: 31 additions & 19 deletions app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt
Expand Up @@ -10,16 +10,13 @@ import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.browser.state.selector.normalTabs
import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.state.selector.selectedTab
import mozilla.components.browser.state.store.BrowserStore
import org.mozilla.fenix.sync.SyncedTabsAdapter
import org.mozilla.fenix.tabstray.browser.BrowserTabsAdapter
import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor
import org.mozilla.fenix.tabstray.browser.TitleHeaderAdapter
import org.mozilla.fenix.tabstray.browser.InactiveTabsAdapter
import org.mozilla.fenix.tabstray.browser.maxActiveTime
import org.mozilla.fenix.tabstray.ext.isNormalTabActive
import org.mozilla.fenix.tabstray.browser.TabGroupAdapter
import org.mozilla.fenix.tabstray.syncedtabs.TabClickDelegate
import org.mozilla.fenix.tabstray.viewholders.AbstractPageViewHolder
import org.mozilla.fenix.tabstray.viewholders.NormalBrowserPageViewHolder
Expand All @@ -28,48 +25,62 @@ import org.mozilla.fenix.tabstray.viewholders.SyncedTabsPageViewHolder

class TrayPagerAdapter(
@VisibleForTesting internal val context: Context,
@VisibleForTesting internal val store: TabsTrayStore,
@VisibleForTesting internal val tabsTrayStore: TabsTrayStore,
@VisibleForTesting internal val browserInteractor: BrowserTrayInteractor,
@VisibleForTesting internal val navInteractor: NavigationInteractor,
@VisibleForTesting internal val interactor: TabsTrayInteractor,
@VisibleForTesting internal val browserStore: BrowserStore
) : RecyclerView.Adapter<AbstractPageViewHolder>() {

/**
* ⚠️ N.B: Scrolling to the selected tab depends on the order of these adapters. If you change
* the ordering or add/remove an adapter, please update [NormalBrowserPageViewHolder.scrollToTab] and
* the layout manager.
*/
private val normalAdapter by lazy {
ConcatAdapter(
BrowserTabsAdapter(context, browserInteractor, store, TABS_TRAY_FEATURE_NAME),
InactiveTabsAdapter(context, browserInteractor, INACTIVE_TABS_FEATURE_NAME)
InactiveTabsAdapter(context, browserInteractor, INACTIVE_TABS_FEATURE_NAME),
TabGroupAdapter(context, browserInteractor, tabsTrayStore, TAB_GROUP_FEATURE_NAME),
TitleHeaderAdapter(browserStore),
BrowserTabsAdapter(context, browserInteractor, tabsTrayStore, TABS_TRAY_FEATURE_NAME)
)
}
private val privateAdapter by lazy { BrowserTabsAdapter(context, browserInteractor, store, TABS_TRAY_FEATURE_NAME) }
private val syncedTabsAdapter by lazy { SyncedTabsAdapter(TabClickDelegate(navInteractor)) }
private val privateAdapter by lazy {
BrowserTabsAdapter(
context,
browserInteractor,
tabsTrayStore,
TABS_TRAY_FEATURE_NAME
)
}
private val syncedTabsAdapter by lazy {
SyncedTabsAdapter(TabClickDelegate(navInteractor))
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractPageViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(viewType, parent, false)

val selectedTab = browserStore.state.selectedTab

return when (viewType) {
NormalBrowserPageViewHolder.LAYOUT_ID -> {
NormalBrowserPageViewHolder(
itemView,
store,
interactor,
browserStore.state.normalTabs.filter { it.isNormalTabActive(maxActiveTime) }.indexOf(selectedTab)
tabsTrayStore,
browserStore,
interactor
)
}
PrivateBrowserPageViewHolder.LAYOUT_ID -> {
PrivateBrowserPageViewHolder(
itemView,
store,
interactor,
browserStore.state.privateTabs.indexOf(selectedTab)
tabsTrayStore,
browserStore,
interactor
)
}
SyncedTabsPageViewHolder.LAYOUT_ID -> {
SyncedTabsPageViewHolder(
itemView,
store
tabsTrayStore
)
}
else -> throw IllegalStateException("Unknown viewType.")
Expand Down Expand Up @@ -102,6 +113,7 @@ class TrayPagerAdapter(

// Telemetry keys for identifying from which app features the a was opened / closed.
const val TABS_TRAY_FEATURE_NAME = "Tabs tray"
const val TAB_GROUP_FEATURE_NAME = "Tab group"
const val INACTIVE_TABS_FEATURE_NAME = "Inactive tabs"

val POSITION_NORMAL_TABS = Page.NormalTabs.ordinal
Expand Down

This file was deleted.

This file was deleted.

@@ -0,0 +1,120 @@
/* 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.View
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.AppCompatImageButton
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.browser.tabstray.TabsTrayStyling
import mozilla.components.concept.base.images.ImageLoader
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 org.mozilla.fenix.selection.SelectionHolder
import org.mozilla.fenix.tabstray.TabsTrayStore

sealed class BrowserTabViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
/**
* A RecyclerView ViewHolder implementation for "tab" items with grid layout.
*
* @param imageLoader [ImageLoader] used to load tab thumbnails.
* @param browserTrayInteractor [BrowserTrayInteractor] handling tabs interactions in a tab tray.
* @param store [TabsTrayStore] containing the complete state of tabs tray and methods to update that.
* @param selectionHolder [SelectionHolder]<[Tab]> for helping with selecting any number of displayed [Tab]s.
* @param itemView [View] that displays a "tab".
* @param featureName [String] representing the name of the feature displaying tabs. Used in telemetry reporting.
*/
class GridViewHolder(
imageLoader: ImageLoader,
override val browserTrayInteractor: BrowserTrayInteractor,
store: TabsTrayStore,
selectionHolder: SelectionHolder<Tab>? = null,
itemView: View,
featureName: String
) : AbstractBrowserTabViewHolder(itemView, imageLoader, store, selectionHolder, featureName) {

private val closeButton: AppCompatImageButton = itemView.findViewById(R.id.mozac_browser_tabstray_close)

override val thumbnailSize: Int
get() = max(
itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_grid_item_thumbnail_height),
itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_grid_item_thumbnail_width)
)

override fun updateSelectedTabIndicator(showAsSelected: Boolean) {
val binding = TabTrayGridItemBinding.bind(itemView)
binding.tabTrayGridItem.background = if (showAsSelected) {
AppCompatResources.getDrawable(itemView.context, R.drawable.tab_tray_grid_item_selected_border)
} else {
null
}
return
}

override fun bind(
tab: Tab,
isSelected: Boolean,
styling: TabsTrayStyling,
observable: Observable<TabsTray.Observer>
) {
super.bind(tab, isSelected, styling, observable)

closeButton.increaseTapArea(GRID_ITEM_CLOSE_BUTTON_EXTRA_DPS)
}

companion object {
const val LAYOUT_ID = R.layout.tab_tray_grid_item
}
}

/**
* A RecyclerView ViewHolder implementation for "tab" items with list layout.
*
* @param imageLoader [ImageLoader] used to load tab thumbnails.
* @param browserTrayInteractor [BrowserTrayInteractor] handling tabs interactions in a tab tray.
* @param store [TabsTrayStore] containing the complete state of tabs tray and methods to update that.
* @param selectionHolder [SelectionHolder]<[Tab]> for helping with selecting any number of displayed [Tab]s.
* @param itemView [View] that displays a "tab".
* @param featureName [String] representing the name of the feature displaying tabs. Used in telemetry reporting.
*/
class ListViewHolder(
imageLoader: ImageLoader,
override val browserTrayInteractor: BrowserTrayInteractor,
store: TabsTrayStore,
selectionHolder: SelectionHolder<Tab>? = null,
itemView: View,
featureName: String
) : AbstractBrowserTabViewHolder(itemView, imageLoader, store, selectionHolder, featureName) {
override val thumbnailSize: Int
get() = max(
itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_list_item_thumbnail_height),
itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_list_item_thumbnail_width)
)

override fun updateSelectedTabIndicator(showAsSelected: Boolean) {
val color = if (showAsSelected) {
R.color.tab_tray_item_selected_background_normal_theme
} else {
R.color.tab_tray_item_background_normal_theme
}
itemView.setBackgroundColor(
ContextCompat.getColor(
itemView.context,
color
)
)
}

companion object {
const val LAYOUT_ID = R.layout.tab_tray_item
}
}
}