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 4ab37c062..38a3f4637 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 624b10e4c..849ac9e64 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 da12846b9..6cc2921e9 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 868a67403..dddaeceb1 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 000000000..c8edbdf74 --- /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 95f2276dd..370dc17f7 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