2
0
mirror of https://github.com/fork-maintainers/iceraven-browser synced 2024-11-19 09:25:34 +00:00

[fenix] For https://github.com/mozilla-mobile/fenix/issues/21095 add customize home button on the home screen.

This commit is contained in:
Arturo Mejia 2021-09-14 14:22:40 -04:00
parent b057d6a76f
commit 5ce4a31be5
10 changed files with 332 additions and 3 deletions

View File

@ -31,6 +31,7 @@ import org.mozilla.fenix.home.recenttabs.view.RecentTabViewHolder
import org.mozilla.fenix.home.recenttabs.view.RecentTabsHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
@ -163,6 +164,8 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
object OnboardingWhatsNew : AdapterItem(OnboardingWhatsNewViewHolder.LAYOUT_ID)
object CustomizeHomeButton : AdapterItem(CustomizeHomeButtonViewHolder.LAYOUT_ID)
object RecentTabsHeader : AdapterItem(RecentTabsHeaderViewHolder.LAYOUT_ID)
object RecentTabItem : AdapterItem(RecentTabViewHolder.LAYOUT_ID)
@ -250,7 +253,7 @@ class SessionControlAdapter(
) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
// This method triggers the ComplexMethod lint error when in fact it's quite simple.
@SuppressWarnings("ComplexMethod")
@SuppressWarnings("ComplexMethod", "LongMethod")
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when (viewType) {
PocketStoriesViewHolder.LAYOUT_ID -> return PocketStoriesViewHolder(
@ -304,6 +307,7 @@ class SessionControlAdapter(
view,
interactor
)
CustomizeHomeButtonViewHolder.LAYOUT_ID -> CustomizeHomeButtonViewHolder(view, interactor)
OnboardingFinishViewHolder.LAYOUT_ID -> OnboardingFinishViewHolder(view, interactor)
OnboardingWhatsNewViewHolder.LAYOUT_ID -> OnboardingWhatsNewViewHolder(view, interactor)
OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID -> OnboardingToolbarPositionPickerViewHolder(

View File

@ -187,6 +187,11 @@ interface SessionControlController {
* @see [TabSessionInteractor.onPrivateModeButtonClicked]
*/
fun handlePrivateModeButtonClicked(newMode: BrowsingMode, userHasBeenOnboarded: Boolean)
/**
* @see [CustomizeHomeIteractor.openCustomizeHomePage]
*/
fun handleCustomizeHomeTapped()
}
@Suppress("TooManyFunctions", "LargeClass")
@ -452,6 +457,11 @@ class DefaultSessionControlController(
navController.nav(R.id.homeFragment, directions)
}
override fun handleCustomizeHomeTapped() {
val directions = HomeFragmentDirections.actionGlobalCustomizationFragment()
navController.nav(R.id.homeFragment, directions)
}
override fun handleWhatsNewGetAnswersClicked() {
activity.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getWhatsNewUrl(activity),

View File

@ -165,6 +165,13 @@ interface TipInteractor {
fun onCloseTip(tip: Tip)
}
interface CustomizeHomeIteractor {
/**
* Opens the customize home settings page.
*/
fun openCustomizeHomePage()
}
/**
* Interface for top site related actions in the [SessionControlInteractor].
*/
@ -237,7 +244,8 @@ class SessionControlInteractor(
ExperimentCardInteractor,
RecentTabInteractor,
RecentBookmarksInteractor,
HistoryMetadataInteractor {
HistoryMetadataInteractor,
CustomizeHomeIteractor {
override fun onCollectionAddTabTapped(collection: TabCollection) {
controller.handleCollectionAddTabTapped(collection)
@ -376,4 +384,8 @@ class SessionControlInteractor(
historyMetadataGroup
)
}
override fun openCustomizeHomePage() {
controller.handleCustomizeHomeTapped()
}
}

View File

@ -6,6 +6,7 @@ package org.mozilla.fenix.home.sessioncontrol
import android.content.Context
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
@ -28,7 +29,8 @@ import org.mozilla.fenix.home.OnboardingState
// This method got a little complex with the addition of the tab tray feature flag
// When we remove the tabs from the home screen this will get much simpler again.
@Suppress("ComplexMethod", "LongParameterList")
private fun normalModeAdapterItems(
@VisibleForTesting
internal fun normalModeAdapterItems(
context: Context,
topSites: List<TopSite>,
collections: List<TabCollection>,
@ -42,6 +44,7 @@ private fun normalModeAdapterItems(
pocketArticles: List<PocketRecommendedStory>
): List<AdapterItem> {
val items = mutableListOf<AdapterItem>()
var shouldShowCustomizeHome = false
tip?.let { items.add(AdapterItem.TipItem(it)) }
@ -54,15 +57,18 @@ private fun normalModeAdapterItems(
}
if (recentTabs.isNotEmpty()) {
shouldShowCustomizeHome = true
items.add(AdapterItem.RecentTabsHeader)
items.add(AdapterItem.RecentTabItem)
}
if (recentBookmarks.isNotEmpty()) {
shouldShowCustomizeHome = true
items.add(AdapterItem.RecentBookmarks(recentBookmarks))
}
if (historyMetadata.isNotEmpty()) {
shouldShowCustomizeHome = true
showHistoryMetadata(historyMetadata, items)
}
@ -75,9 +81,14 @@ private fun normalModeAdapterItems(
}
if (context.settings().pocketRecommendations && pocketArticles.isNotEmpty()) {
shouldShowCustomizeHome = true
items.add(AdapterItem.PocketStoriesItem)
}
if (shouldShowCustomizeHome) {
items.add(AdapterItem.CustomizeHomeButton)
}
return items
}

View File

@ -0,0 +1,29 @@
/* 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.home.sessioncontrol.viewholders
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.CustomizeHomeListItemBinding
import org.mozilla.fenix.home.sessioncontrol.CustomizeHomeIteractor
class CustomizeHomeButtonViewHolder(
view: View,
private val interactor: CustomizeHomeIteractor
) : RecyclerView.ViewHolder(view) {
init {
val binding = CustomizeHomeListItemBinding.bind(view)
binding.customizeHome.setOnClickListener {
interactor.openCustomizeHomePage()
}
}
companion object {
const val LAYOUT_ID = R.layout.customize_home_list_item
}
}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/about_list_item_height"
android:background="?android:attr/selectableItemBackground">
<Button
android:id="@+id/customize_home"
style="@style/NeutralOnboardingButton"
android:layout_height="36dp"
android:background="@drawable/rounded_button_background"
android:clickable="false"
android:focusable="false"
android:text="@string/browser_menu_customize_home"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -162,6 +162,20 @@ class DefaultSessionControlControllerTest {
}
}
@Test
fun handleCustomizeHomeTapped() {
createController().handleCustomizeHomeTapped()
verify {
navController.navigate(
match<NavDirections> {
it.actionId == R.id.action_global_customizationFragment
},
null
)
}
}
@Test
fun `handleCollectionOpenTabClicked onFailure`() {
val tab = mockk<ComponentTab> {

View File

@ -223,6 +223,12 @@ class SessionControlInteractorTest {
verify { recentBookmarksController.handleBookmarkClicked(bookmark) }
}
@Test
fun `WHEN tapping on the customize home button THEN openCustomizeHomePage`() {
interactor.openCustomizeHomePage()
verify { controller.handleCustomizeHomeTapped() }
}
@Test
fun `WHEN Show All recently saved bookmarks button is clicked THEN the click is handled`() {
interactor.onShowAllBookmarksClicked()

View File

@ -0,0 +1,40 @@
/* 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.home.sessioncontrol
import android.view.LayoutInflater
import io.mockk.mockk
import io.mockk.verify
import mozilla.components.support.test.robolectric.testContext
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.databinding.CustomizeHomeListItemBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonViewHolder
@RunWith(FenixRobolectricTestRunner::class)
class CustomizeHomeButtonViewHolderTest {
private lateinit var binding: CustomizeHomeListItemBinding
private lateinit var interactor: CustomizeHomeIteractor
@Before
fun setup() {
binding = CustomizeHomeListItemBinding.inflate(LayoutInflater.from(testContext))
interactor = mockk(relaxed = true)
}
@Test
fun `hide view and change setting on remove placeholder click`() {
CustomizeHomeButtonViewHolder(binding.root, interactor)
binding.customizeHome.performClick()
verify {
interactor.openCustomizeHomePage()
}
}
}

View File

@ -0,0 +1,177 @@
/* 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.home.sessioncontrol
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite
import mozilla.components.service.pocket.PocketRecommendedStory
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.historymetadata.HistoryMetadataGroup
import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class SessionControlViewTest {
@Test
fun `GIVEN recent Bookmarks WHEN normalModeAdapterItems is called THEN add a customize home button`() {
val topSites = emptyList<TopSite>()
val collections = emptyList<TabCollection>()
val expandedCollections = emptySet<Long>()
val recentBookmarks =
listOf(BookmarkNode(BookmarkNodeType.ITEM, "guid", null, null, null, null, 0, null))
val recentTabs = emptyList<TabSessionState>()
val historyMetadata = emptyList<HistoryMetadataGroup>()
val pocketArticles = emptyList<PocketRecommendedStory>()
val results = normalModeAdapterItems(
testContext,
topSites,
collections,
expandedCollections,
null,
recentBookmarks,
false,
false,
recentTabs,
historyMetadata,
pocketArticles
)
assertTrue(results[0] is AdapterItem.RecentBookmarks)
assertTrue(results[1] is AdapterItem.CustomizeHomeButton)
}
@Test
fun `GIVEN recent tabs WHEN normalModeAdapterItems is called THEN add a customize home button`() {
val topSites = emptyList<TopSite>()
val collections = emptyList<TabCollection>()
val expandedCollections = emptySet<Long>()
val recentBookmarks = listOf<BookmarkNode>()
val recentTabs = listOf<TabSessionState>(mockk())
val historyMetadata = emptyList<HistoryMetadataGroup>()
val pocketArticles = emptyList<PocketRecommendedStory>()
val results = normalModeAdapterItems(
testContext,
topSites,
collections,
expandedCollections,
null,
recentBookmarks,
false,
false,
recentTabs,
historyMetadata,
pocketArticles
)
assertTrue(results[0] is AdapterItem.RecentTabsHeader)
assertTrue(results[1] is AdapterItem.RecentTabItem)
assertTrue(results[2] is AdapterItem.CustomizeHomeButton)
}
@Test
fun `GIVEN history metadata WHEN normalModeAdapterItems is called THEN add a customize home button`() {
val topSites = emptyList<TopSite>()
val collections = emptyList<TabCollection>()
val expandedCollections = emptySet<Long>()
val recentBookmarks = listOf<BookmarkNode>()
val recentTabs = emptyList<TabSessionState>()
val historyMetadata = listOf(HistoryMetadataGroup("title", emptyList(), false))
val pocketArticles = emptyList<PocketRecommendedStory>()
val results = normalModeAdapterItems(
testContext,
topSites,
collections,
expandedCollections,
null,
recentBookmarks,
false,
false,
recentTabs,
historyMetadata,
pocketArticles
)
assertTrue(results[0] is AdapterItem.HistoryMetadataHeader)
assertTrue(results[1] is AdapterItem.HistoryMetadataGroup)
assertTrue(results[2] is AdapterItem.CustomizeHomeButton)
}
@Test
fun `GIVEN pocket articles WHEN normalModeAdapterItems is called THEN add a customize home button`() {
val topSites = emptyList<TopSite>()
val collections = emptyList<TabCollection>()
val expandedCollections = emptySet<Long>()
val recentBookmarks = listOf<BookmarkNode>()
val recentTabs = emptyList<TabSessionState>()
val historyMetadata = emptyList<HistoryMetadataGroup>()
val pocketArticles = listOf(PocketRecommendedStory("", "", "", "", 0, ""))
val context = spyk(testContext)
val settings: Settings = mockk()
every { settings.pocketRecommendations } returns true
every { context.settings() } returns settings
val results = normalModeAdapterItems(
context,
topSites,
collections,
expandedCollections,
null,
recentBookmarks,
false,
false,
recentTabs,
historyMetadata,
pocketArticles
)
assertTrue(results[0] is AdapterItem.PocketStoriesItem)
assertTrue(results[1] is AdapterItem.CustomizeHomeButton)
}
@Test
fun `GIVEN none recentBookmarks,recentTabs, historyMetadata or pocketArticles WHEN normalModeAdapterItems is called THEN the customize home button is not added`() {
val topSites = emptyList<TopSite>()
val collections = emptyList<TabCollection>()
val expandedCollections = emptySet<Long>()
val recentBookmarks = listOf<BookmarkNode>()
val recentTabs = emptyList<TabSessionState>()
val historyMetadata = emptyList<HistoryMetadataGroup>()
val pocketArticles = emptyList<PocketRecommendedStory>()
val context = spyk(testContext)
val settings: Settings = mockk()
every { settings.pocketRecommendations } returns true
every { context.settings() } returns settings
val results = normalModeAdapterItems(
context,
topSites,
collections,
expandedCollections,
null,
recentBookmarks,
false,
false,
recentTabs,
historyMetadata,
pocketArticles
)
assertTrue(results.isEmpty())
}
}