diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt
index 4ab37c062e..38a3f46379 100644
--- a/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt
+++ b/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt
@@ -19,6 +19,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
+import org.mozilla.fenix.ext.settings
class FenixTabsAdapter(
private val context: Context,
@@ -27,7 +28,7 @@ class FenixTabsAdapter(
viewHolderProvider = { parentView ->
TabTrayViewHolder(
LayoutInflater.from(context).inflate(
- R.layout.tab_tray_item,
+ if (context.settings().gridTabView) R.layout.tab_tray_grid_item else R.layout.tab_tray_item,
parentView,
false
),
diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt
index 624b10e4c4..849ac9e641 100644
--- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt
+++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt
@@ -162,6 +162,13 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
if (newConfig.orientation != currentOrientation) {
tabTrayView.dismissMenu()
tabTrayView.expand()
+
+ if (requireContext().settings().gridTabView) {
+ // Update the number of columns to use in the grid view when the screen
+ // orientation changes.
+ tabTrayView.updateTabsTrayLayout()
+ }
+
currentOrientation = newConfig.orientation
}
}
diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt
index da12846b9a..6cc2921e95 100644
--- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt
+++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt
@@ -22,6 +22,7 @@ import androidx.core.view.updatePadding
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter
+import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.tabs.TabLayout
@@ -174,11 +175,9 @@ class TabTrayView(
)
}
+ updateTabsTrayLayout()
+
view.tabsTray.apply {
- layoutManager = LinearLayoutManager(container.context).apply {
- reverseLayout = true
- stackFromEnd = true
- }
adapter = concatAdapter
tabsTouchHelper = TabsTouchHelper(
@@ -190,11 +189,15 @@ class TabTrayView(
tabsAdapter.tabTrayInteractor = interactor
tabsAdapter.onTabsUpdated = {
- // Put the 'Add to collections' button after the tabs have loaded.
- concatAdapter.addAdapter(0, collectionsButtonAdapter)
-
- // Put the Synced Tabs adapter at the end.
- concatAdapter.addAdapter(0, syncedTabsController.adapter)
+ if (view.context.settings().gridTabView) {
+ concatAdapter.addAdapter(collectionsButtonAdapter)
+ concatAdapter.addAdapter(syncedTabsController.adapter)
+ } else {
+ // Put the 'Add to collections' button after the tabs have loaded.
+ concatAdapter.addAdapter(0, collectionsButtonAdapter)
+ // Put the Synced Tabs adapter at the end.
+ concatAdapter.addAdapter(syncedTabsController.adapter)
+ }
if (hasAccessibilityEnabled) {
tabsAdapter.notifyItemRangeChanged(0, tabs.size)
@@ -345,6 +348,53 @@ class TabTrayView(
var mode: Mode = Mode.Normal
private set
+ fun updateTabsTrayLayout() {
+ if (container.context.settings().gridTabView) {
+ setupGridTabView()
+ } else {
+ setupListTabView()
+ }
+ }
+
+ private fun setupGridTabView() {
+ view.tabsTray.apply {
+ val gridLayoutManager =
+ GridLayoutManager(container.context, getNumberOfGridColumns(container.context))
+
+ gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+ override fun getSpanSize(position: Int): Int {
+ val numTabs = tabsAdapter.itemCount
+ return if (position < numTabs) {
+ 1
+ } else {
+ getNumberOfGridColumns(container.context)
+ }
+ }
+ }
+
+ layoutManager = gridLayoutManager
+ }
+ }
+
+ /**
+ * Returns the number of columns that will fit in the grid layout for the current screen.
+ */
+ private fun getNumberOfGridColumns(context: Context): Int {
+ val displayMetrics = context.resources.displayMetrics
+ val screenWidthDp = displayMetrics.widthPixels / displayMetrics.density
+ val columnCount = (screenWidthDp / COLUMN_WIDTH_DP).toInt()
+ return if (columnCount >= 2) columnCount else 2
+ }
+
+ private fun setupListTabView() {
+ view.tabsTray.apply {
+ layoutManager = LinearLayoutManager(container.context).apply {
+ reverseLayout = true
+ stackFromEnd = true
+ }
+ }
+ }
+
fun updateState(state: TabTrayDialogFragmentState) {
val oldMode = mode
@@ -620,6 +670,7 @@ class TabTrayView(
private const val SLIDE_OFFSET = 0
private const val SELECTION_DELAY = 500
private const val NORMAL_HANDLE_PERCENT_WIDTH = 0.1F
+ private const val COLUMN_WIDTH_DP = 180
}
}
diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt
index 868a67403a..dddaeceb1c 100644
--- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt
+++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt
@@ -34,6 +34,7 @@ import org.mozilla.fenix.ext.getMediaStateForSession
import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.ext.removeAndDisable
import org.mozilla.fenix.ext.removeTouchDelegate
+import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showAndEnable
import org.mozilla.fenix.ext.toShortUrl
import org.mozilla.fenix.utils.Do
@@ -161,6 +162,11 @@ class TabTrayViewHolder(
@VisibleForTesting
internal fun updateBackgroundColor(isSelected: Boolean) {
+ if (itemView.context.settings().gridTabView) {
+ // No need to set a background color in the item view for grid tabs.
+ return
+ }
+
val color = if (isSelected) {
R.color.tab_tray_item_selected_background_normal_theme
} else {
@@ -180,10 +186,17 @@ class TabTrayViewHolder(
}
private fun loadIntoThumbnailView(thumbnailView: ImageView, id: String) {
- val thumbnailSize = max(
- itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_thumbnail_height),
- itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_thumbnail_width)
- )
+ val thumbnailSize = if (itemView.context.settings().gridTabView) {
+ max(
+ itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_grid_item_thumbnail_height),
+ itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_grid_item_thumbnail_width)
+ )
+ } else {
+ max(
+ itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_list_item_thumbnail_height),
+ itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_list_item_thumbnail_width)
+ )
+ }
imageLoader.loadIntoView(thumbnailView, ImageLoadRequest(id, thumbnailSize))
}
diff --git a/app/src/main/res/layout/tab_tray_grid_item.xml b/app/src/main/res/layout/tab_tray_grid_item.xml
new file mode 100644
index 0000000000..c8edbdf74d
--- /dev/null
+++ b/app/src/main/res/layout/tab_tray_grid_item.xml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/tab_tray_item.xml b/app/src/main/res/layout/tab_tray_item.xml
index 95f2276ddb..370dc17f76 100644
--- a/app/src/main/res/layout/tab_tray_item.xml
+++ b/app/src/main/res/layout/tab_tray_item.xml
@@ -28,8 +28,8 @@
40dp
- 92dp
- 69dp
+ 92dp
+ 69dp
+ 156dp
+ 156dp
+ 8dp
+ 2dp
4dp
11dp
0dp