[fenix] For https://github.com/mozilla-mobile/fenix/issues/24235 - Remove Tip from HomeFragmentStore
parent
082705a3c6
commit
13af68853e
@ -1,39 +0,0 @@
|
|||||||
/* 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.components.tips
|
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
|
|
||||||
sealed class TipType {
|
|
||||||
data class Button(val text: String, val action: () -> Unit) : TipType()
|
|
||||||
}
|
|
||||||
|
|
||||||
open class Tip(
|
|
||||||
val type: TipType,
|
|
||||||
val identifier: String,
|
|
||||||
val title: String,
|
|
||||||
val description: String,
|
|
||||||
val learnMoreURL: String?,
|
|
||||||
val titleDrawable: Drawable? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
interface TipProvider {
|
|
||||||
val tip: Tip?
|
|
||||||
val shouldDisplay: Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TipManager {
|
|
||||||
fun getTip(): Tip?
|
|
||||||
}
|
|
||||||
|
|
||||||
class FenixTipManager(
|
|
||||||
private val providers: List<TipProvider>
|
|
||||||
) : TipManager {
|
|
||||||
override fun getTip(): Tip? {
|
|
||||||
return providers
|
|
||||||
.firstOrNull { it.shouldDisplay }
|
|
||||||
?.tip
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/* 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.tips
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import org.mozilla.fenix.BrowserDirection
|
|
||||||
import org.mozilla.fenix.HomeActivity
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.components.tips.Tip
|
|
||||||
import org.mozilla.fenix.components.tips.TipType
|
|
||||||
import org.mozilla.fenix.databinding.ButtonTipItemBinding
|
|
||||||
import org.mozilla.fenix.ext.addUnderline
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
import org.mozilla.fenix.utils.view.ViewHolder
|
|
||||||
|
|
||||||
class ButtonTipViewHolder(
|
|
||||||
private val view: View,
|
|
||||||
private val interactor: SessionControlInteractor,
|
|
||||||
private val settings: Settings = view.context.components.settings
|
|
||||||
) : ViewHolder(view) {
|
|
||||||
|
|
||||||
var tip: Tip? = null
|
|
||||||
|
|
||||||
fun bind(tip: Tip) {
|
|
||||||
val binding = ButtonTipItemBinding.bind(view)
|
|
||||||
require(tip.type is TipType.Button)
|
|
||||||
|
|
||||||
this.tip = tip
|
|
||||||
|
|
||||||
with(binding) {
|
|
||||||
tipHeaderText.text = tip.title
|
|
||||||
tip.titleDrawable?.let {
|
|
||||||
tipHeaderText.setCompoundDrawablesWithIntrinsicBounds(it, null, null, null)
|
|
||||||
}
|
|
||||||
tipDescriptionText.text = tip.description
|
|
||||||
tipButton.text = tip.type.text
|
|
||||||
|
|
||||||
tipLearnMore.isVisible = tip.learnMoreURL != null
|
|
||||||
if (tip.learnMoreURL != null) {
|
|
||||||
tipLearnMore.addUnderline()
|
|
||||||
|
|
||||||
tipLearnMore.setOnClickListener {
|
|
||||||
(itemView.context as HomeActivity).openToBrowserAndLoad(
|
|
||||||
searchTermOrURL = tip.learnMoreURL,
|
|
||||||
newTab = true,
|
|
||||||
from = BrowserDirection.FromHome
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tipButton.setOnClickListener {
|
|
||||||
tip.type.action.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
tipClose.setOnClickListener {
|
|
||||||
settings.preferences
|
|
||||||
.edit()
|
|
||||||
.putBoolean(tip.identifier, false)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
interactor.onCloseTip(tip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val LAYOUT_ID = R.layout.button_tip_item
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
<?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"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/tip_card"
|
|
||||||
style="@style/OnboardingCardLight"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="@dimen/home_item_horizontal_margin"
|
|
||||||
android:background="@drawable/cfr_background_gradient">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tip_header_text"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:drawablePadding="12dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:lineSpacingExtra="2dp"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:textAppearance="@style/HeaderTextStyle"
|
|
||||||
android:textColor="@color/photonLightGrey05"
|
|
||||||
app:drawableTint="@color/photonLightGrey05"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/tip_close"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="Header text" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/tip_close"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/create_collection_close"
|
|
||||||
app:tint="@color/photonLightGrey05"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_close" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tip_description_text"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:lineSpacingExtra="2dp"
|
|
||||||
android:textAppearance="@style/Body14TextStyle"
|
|
||||||
android:textColor="@color/photonLightGrey05"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/tip_close"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tip_header_text"
|
|
||||||
tools:text="Tip description" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tip_learn_more"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/search_suggestions_onboarding_learn_more_link"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:textColor="@color/photonLightGrey05"
|
|
||||||
app:layout_constraintEnd_toEndOf="@id/tip_description_text"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/tip_description_text"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tip_description_text"
|
|
||||||
tools:textColor="@color/accent_high_contrast_private_theme" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/tip_button"
|
|
||||||
style="@style/NeutralButton"
|
|
||||||
android:layout_height="36dp"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
app:backgroundTint="@color/photonLightGrey20"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tip_learn_more"
|
|
||||||
tools:text="Call to action" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,46 +0,0 @@
|
|||||||
/* 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.components.tips
|
|
||||||
|
|
||||||
import io.mockk.mockk
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Assert.assertNull
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class TipManagerTest {
|
|
||||||
@Test
|
|
||||||
fun `test first with shouldDisplay`() {
|
|
||||||
val shouldDisplayProvider = object : TipProvider {
|
|
||||||
override val tip = mockk<Tip>()
|
|
||||||
override val shouldDisplay = true
|
|
||||||
}
|
|
||||||
val shouldNotDisplayProvider = object : TipProvider {
|
|
||||||
override val tip = mockk<Tip>()
|
|
||||||
override val shouldDisplay = false
|
|
||||||
}
|
|
||||||
val manager = FenixTipManager(listOf(shouldNotDisplayProvider, shouldDisplayProvider))
|
|
||||||
assertEquals(shouldDisplayProvider.tip, manager.getTip())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `test first with shouldDisplay even if tip is null`() {
|
|
||||||
val shouldDisplayProvider = object : TipProvider {
|
|
||||||
override val tip: Tip? = null
|
|
||||||
override val shouldDisplay = true
|
|
||||||
}
|
|
||||||
val shouldNotDisplayProvider = object : TipProvider {
|
|
||||||
override val tip = mockk<Tip>()
|
|
||||||
override val shouldDisplay = false
|
|
||||||
}
|
|
||||||
val manager = FenixTipManager(listOf(shouldNotDisplayProvider, shouldDisplayProvider))
|
|
||||||
assertEquals(shouldDisplayProvider.tip, manager.getTip())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `test returns null with empty list`() {
|
|
||||||
val manager = FenixTipManager(emptyList())
|
|
||||||
assertNull(manager.getTip())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
/* 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.tips
|
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import androidx.core.view.isGone
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import io.mockk.MockKAnnotations
|
|
||||||
import io.mockk.Runs
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.impl.annotations.MockK
|
|
||||||
import io.mockk.just
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.spyk
|
|
||||||
import io.mockk.verify
|
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mozilla.fenix.BrowserDirection
|
|
||||||
import org.mozilla.fenix.HomeActivity
|
|
||||||
import org.mozilla.fenix.components.tips.Tip
|
|
||||||
import org.mozilla.fenix.components.tips.TipType
|
|
||||||
import org.mozilla.fenix.databinding.ButtonTipItemBinding
|
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
|
||||||
class ButtonTipViewHolderTest {
|
|
||||||
|
|
||||||
@MockK private lateinit var activity: HomeActivity
|
|
||||||
@MockK private lateinit var interactor: SessionControlInteractor
|
|
||||||
@MockK private lateinit var settings: Settings
|
|
||||||
@MockK private lateinit var sharedPrefs: SharedPreferences
|
|
||||||
@MockK private lateinit var sharedPrefsEditor: SharedPreferences.Editor
|
|
||||||
private lateinit var viewHolder: ButtonTipViewHolder
|
|
||||||
private lateinit var binding: ButtonTipItemBinding
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
MockKAnnotations.init(this)
|
|
||||||
val view = spyk(
|
|
||||||
LayoutInflater.from(testContext)
|
|
||||||
.inflate(ButtonTipViewHolder.LAYOUT_ID, null)
|
|
||||||
)
|
|
||||||
|
|
||||||
viewHolder = ButtonTipViewHolder(view, interactor, settings)
|
|
||||||
binding = ButtonTipItemBinding.bind(view)
|
|
||||||
every { view.context } returns activity
|
|
||||||
every { activity.openToBrowserAndLoad(any(), any(), any()) } just Runs
|
|
||||||
every { interactor.onCloseTip(any()) } just Runs
|
|
||||||
every { settings.preferences } returns sharedPrefs
|
|
||||||
every { sharedPrefs.edit() } returns sharedPrefsEditor
|
|
||||||
every { sharedPrefsEditor.putBoolean(any(), any()) } returns sharedPrefsEditor
|
|
||||||
every { sharedPrefsEditor.apply() } just Runs
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `text is displayed based on given tip`() {
|
|
||||||
viewHolder.bind(defaultTip())
|
|
||||||
|
|
||||||
assertEquals("Tip Title", binding.tipHeaderText.text)
|
|
||||||
assertEquals("Tip description", binding.tipDescriptionText.text)
|
|
||||||
assertEquals("button", binding.tipButton.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `learn more is hidden if learnMoreURL is null`() {
|
|
||||||
viewHolder.bind(defaultTip(learnMoreUrl = null))
|
|
||||||
|
|
||||||
assertTrue(binding.tipLearnMore.isGone)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `learn more is visible if learnMoreURL is not null`() {
|
|
||||||
viewHolder.bind(defaultTip(learnMoreUrl = "https://learnmore.com"))
|
|
||||||
|
|
||||||
assertTrue(binding.tipLearnMore.isVisible)
|
|
||||||
|
|
||||||
binding.tipLearnMore.performClick()
|
|
||||||
verify {
|
|
||||||
activity.openToBrowserAndLoad(
|
|
||||||
searchTermOrURL = "https://learnmore.com",
|
|
||||||
newTab = true,
|
|
||||||
from = BrowserDirection.FromHome
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `tip button invokes tip action`() {
|
|
||||||
val action = mockk<() -> Unit>(relaxed = true)
|
|
||||||
viewHolder.bind(defaultTip(action))
|
|
||||||
|
|
||||||
binding.tipButton.performClick()
|
|
||||||
verify { action() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `close button invokes onCloseTip`() {
|
|
||||||
val tip = defaultTip()
|
|
||||||
viewHolder.bind(tip)
|
|
||||||
|
|
||||||
binding.tipClose.performClick()
|
|
||||||
verify { interactor.onCloseTip(tip) }
|
|
||||||
verify { sharedPrefsEditor.putBoolean("tipIdentifier", false) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun defaultTip(
|
|
||||||
action: () -> Unit = mockk(),
|
|
||||||
learnMoreUrl: String? = null
|
|
||||||
) = Tip(
|
|
||||||
type = TipType.Button("button", action),
|
|
||||||
identifier = "tipIdentifier",
|
|
||||||
title = "Tip Title",
|
|
||||||
description = "Tip description",
|
|
||||||
learnMoreURL = learnMoreUrl
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in New Issue