diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt index 5ceead5e4..2b020e905 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt @@ -77,7 +77,8 @@ class TabsTrayFragment : AppCompatDialogFragment(), TabsTrayInteractor { val browserTrayInteractor = DefaultBrowserTrayInteractor( this, selectTabUseCase, - removeUseCases + removeUseCases, + requireComponents.settings ) val syncedTabsTrayInteractor = SyncedTabsInteractor( diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt index 6fdf2b3e6..0249ceb25 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.tabstray import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup -import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import org.mozilla.fenix.tabstray.browser.BrowserTabsAdapter import org.mozilla.fenix.tabstray.browser.BrowserTrayInteractor @@ -57,7 +56,7 @@ class TrayPagerAdapter( else -> throw IllegalStateException("View type does not exist.") } - viewHolder.bind(adapter, GridLayoutManager(context, 1)) + viewHolder.bind(adapter, browserInteractor.getLayoutManagerForPosition(context, position)) } override fun getItemViewType(position: Int): Int { diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt index 8fffdb913..20b65e223 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/BrowserTrayInteractor.kt @@ -4,9 +4,15 @@ package org.mozilla.fenix.tabstray.browser +import android.content.Context +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import mozilla.components.concept.tabstray.Tab import mozilla.components.feature.tabs.TabsUseCases import org.mozilla.fenix.tabstray.TabsTrayInteractor +import org.mozilla.fenix.tabstray.TrayPagerAdapter +import org.mozilla.fenix.tabstray.ext.numberOfGridColumns +import org.mozilla.fenix.utils.Settings /** * For interacting with UI that is specifically for [BaseBrowserTrayList] and other browser @@ -28,6 +34,11 @@ interface BrowserTrayInteractor { * If multi-select mode is enabled or disabled. */ fun isMultiSelectMode(): Boolean + + /** + * Returns the appropriate [RecyclerView.LayoutManager] to be used at [position]. + */ + fun getLayoutManagerForPosition(context: Context, position: Int): RecyclerView.LayoutManager } /** @@ -36,7 +47,8 @@ interface BrowserTrayInteractor { class DefaultBrowserTrayInteractor( private val trayInteractor: TabsTrayInteractor, private val selectTabUseCase: TabsUseCases.SelectTabUseCase, - private val removeUseCases: TabsUseCases.RemoveTabUseCase + private val removeUseCases: TabsUseCases.RemoveTabUseCase, + private val settings: Settings ) : BrowserTrayInteractor { /** @@ -61,4 +73,23 @@ class DefaultBrowserTrayInteractor( // Needs https://github.com/mozilla-mobile/fenix/issues/18513 to change this value return false } + + override fun getLayoutManagerForPosition( + context: Context, + position: Int + ): RecyclerView.LayoutManager { + if (position == TrayPagerAdapter.POSITION_SYNCED_TABS) { + // Lists are just Grids with one column :) + return GridLayoutManager(context, 1) + } + + // Normal/Private tabs + val numberOfColumns = if (settings.gridTabView) { + context.numberOfGridColumns + } else { + 1 + } + + return GridLayoutManager(context, numberOfColumns) + } } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/ext/Context.kt b/app/src/main/java/org/mozilla/fenix/tabstray/ext/Context.kt new file mode 100644 index 000000000..82f522ec6 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabstray/ext/Context.kt @@ -0,0 +1,19 @@ +/* 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.ext + +import android.content.Context + +private const val MIN_COLUMN_WIDTH_DP = 180 + +/** + * Returns the number of grid columns we can fit on the screen in the tabs tray. + */ +internal val Context.numberOfGridColumns: Int + get() { + val displayMetrics = resources.displayMetrics + val screenWidthDp = displayMetrics.widthPixels / displayMetrics.density + return (screenWidthDp / MIN_COLUMN_WIDTH_DP).toInt() + } diff --git a/app/src/test/java/org/mozilla/fenix/tabstray/browser/DefaultBrowserTrayInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/tabstray/browser/DefaultBrowserTrayInteractorTest.kt new file mode 100644 index 000000000..0b71a107e --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/tabstray/browser/DefaultBrowserTrayInteractorTest.kt @@ -0,0 +1,79 @@ +/* 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.content.Context +import androidx.recyclerview.widget.GridLayoutManager +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.mozilla.fenix.tabstray.TrayPagerAdapter +import org.mozilla.fenix.tabstray.ext.numberOfGridColumns +import org.mozilla.fenix.utils.Settings + +class DefaultBrowserTrayInteractorTest { + + @Before + fun setup() { + mockkStatic("org.mozilla.fenix.tabstray.ext.ContextKt") + } + + @After + fun shutdown() { + unmockkStatic("org.mozilla.fenix.tabstray.ext.ContextKt") + } + + @Test + fun `WHEN pager position is synced tabs THEN return a list layout manager`() { + val interactor = DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), mockk()) + + val result = interactor.getLayoutManagerForPosition( + mockk(), + TrayPagerAdapter.POSITION_SYNCED_TABS + ) + + assertEquals(1, (result as GridLayoutManager).spanCount) + } + + @Test + fun `WHEN setting is grid view THEN return grid layout manager`() { + val context = mockk() + val settings = mockk() + val interactor = DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), settings) + + every { context.numberOfGridColumns }.answers { 4 } + every { settings.gridTabView }.answers { true } + + val result = interactor.getLayoutManagerForPosition( + context, + TrayPagerAdapter.POSITION_NORMAL_TABS + ) + + assertEquals(4, (result as GridLayoutManager).spanCount) + } + + @Test + fun `WHEN setting is list view THEN return list layout manager`() { + val context = mockk() + val settings = mockk() + val interactor = DefaultBrowserTrayInteractor(mockk(), mockk(), mockk(), settings) + + every { context.numberOfGridColumns }.answers { 4 } + every { settings.gridTabView }.answers { false } + + val result = interactor.getLayoutManagerForPosition( + context, + TrayPagerAdapter.POSITION_NORMAL_TABS + ) + + // Should NOT be 4. + assertEquals(1, (result as GridLayoutManager).spanCount) + } +}