Browse Source

FNX-14498 ⁃ For #9487: improve fxa onboarding manual sign in card (#13317)

* Replace strings, add learn more, hook up button

* Constrain learn more and icon to the text

* View holder tests

* Lint

* Update homescreen ui test
master
Elise Richards 2 years ago
committed by GitHub
parent
commit
feae7fff2f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt
  2. 4
      app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt
  3. 24
      app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolder.kt
  4. 22
      app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt
  5. 14
      app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt
  6. 4
      app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt
  7. 16
      app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml
  8. 2
      app/src/main/res/layout/onboarding_automatic_signin.xml
  9. 42
      app/src/main/res/layout/onboarding_manual_signin.xml
  10. 7
      app/src/main/res/values/strings.xml
  11. 14
      app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolderTest.kt
  12. 17
      app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolderTest.kt

4
app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt

@ -553,11 +553,11 @@ private fun assertWelcomeHeader() =
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertGetTheMostHeader() =
onView(allOf(withText("Get the most out of Firefox Preview.")))
onView(allOf(withText("Start syncing bookmarks, passwords, and more with your Firefox account.")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertAccountsSignInButton() =
onView(ViewMatchers.withResourceName("turn_on_sync_button"))
onView(ViewMatchers.withResourceName("fxa_sign_in_button"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertGetToKnowHeader() =

4
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt

@ -31,9 +31,9 @@ class OnboardingAutomaticSignInViewHolder(
private val headerText = view.header_text
init {
view.turn_on_sync_button.setOnClickListener {
view.fxa_sign_in_button.setOnClickListener {
scope.launch {
onClick(it.turn_on_sync_button)
onClick(it.fxa_sign_in_button)
}
}
}

24
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolder.kt

@ -5,40 +5,40 @@
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.view.View
import androidx.core.content.ContextCompat
import androidx.navigation.Navigation
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_manual_signin.view.*
import mozilla.components.support.ktx.android.content.getDrawableWithTint
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.addUnderline
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.home.HomeFragmentDirections
import org.mozilla.fenix.onboarding.OnboardingController
import org.mozilla.fenix.onboarding.OnboardingInteractor
class OnboardingManualSignInViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val headerText = view.header_text
init {
view.turn_on_sync_button.setOnClickListener {
val interactor = OnboardingInteractor(OnboardingController(itemView.context))
view.fxa_sign_in_button.setOnClickListener {
it.context.components.analytics.metrics.track(Event.OnboardingManualSignIn)
val directions = HomeFragmentDirections.actionGlobalTurnOnSync()
Navigation.findNavController(view).navigate(directions)
}
view.learn_more.addUnderline()
view.learn_more.setOnClickListener {
interactor.onLearnMoreClicked()
}
}
fun bind() {
val context = itemView.context
val appName = context.getString(R.string.app_name)
headerText.text = context.getString(R.string.onboarding_firefox_account_header, appName)
val icon = context.getDrawableWithTint(
R.drawable.ic_onboarding_firefox_accounts,
ContextCompat.getColor(context, R.color.white_color)
)
headerText.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon)
headerText.text = context.getString(R.string.onboarding_firefox_account_header)
}
companion object {

22
app/src/main/java/org/mozilla/fenix/onboarding/OnboardingController.kt

@ -0,0 +1,22 @@
/* 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.onboarding
import android.content.Context
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.settings.SupportUtils
class OnboardingController(
private val context: Context
) {
fun handleLearnMoreClicked() {
(context as HomeActivity).openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getFirefoxAccountSumoUrl(),
newTab = true,
from = BrowserDirection.FromHome
)
}
}

14
app/src/main/java/org/mozilla/fenix/onboarding/OnboardingInteractor.kt

@ -0,0 +1,14 @@
/* 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.onboarding
class OnboardingInteractor(private val onboardingController: OnboardingController) {
/**
* Called when the user clicks the learn more link
* @param url the url the suggestion was providing
*/
fun onLearnMoreClicked() = onboardingController.handleLearnMoreClicked()
}

4
app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt

@ -74,6 +74,10 @@ object SupportUtils {
return "https://support.mozilla.org/$langTag/kb/$escapedTopic"
}
fun getFirefoxAccountSumoUrl(): String {
return "https://support.mozilla.org/kb/access-mozilla-services-firefox-account"
}
fun getMozillaPageUrl(page: MozillaPage, locale: Locale = Locale.getDefault()): String {
val path = page.path
val langTag = getLanguageTag(locale)

16
app/src/main/res/drawable/ic_onboarding_avatar_anonymous_large.xml

@ -0,0 +1,16 @@
<?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/. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17.6655,14.2092C16.1843,12.4998 14.1333,14.8 11.9997,14.8C9.8675,14.8 7.8151,12.4998 6.3339,14.2092C5.9139,14.6936 5.8803,15.3992 6.2401,15.9284C7.4959,17.7764 9.5959,19 11.9997,19C14.4035,19 16.5035,17.7764 17.7593,15.9284C18.1205,15.3992 18.0855,14.6936 17.6655,14.2092M16.25,9.25C16.25,6.9026 14.3474,5 12,5C9.6526,5 7.75,6.9026 7.75,9.25C7.75,11.5974 9.6526,13.5 12,13.5C14.3474,13.5 16.25,11.5974 16.25,9.25Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M12,22C6.4772,22 2,17.5228 2,12C2,6.4772 6.4772,2 12,2C17.5228,2 22,6.4772 22,12C21.9939,17.5203 17.5203,21.9939 12,22L12,22ZM12,4C7.5817,4 4,7.5817 4,12C4,16.4183 7.5817,20 12,20C16.4183,20 20,16.4183 20,12C19.995,7.5838 16.4162,4.005 12,4Z" />
</vector>

2
app/src/main/res/layout/onboarding_automatic_signin.xml

@ -22,7 +22,7 @@
tools:text="@string/onboarding_firefox_account_auto_signin_header_2" />
<Button
android:id="@+id/turn_on_sync_button"
android:id="@+id/fxa_sign_in_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"

42
app/src/main/res/layout/onboarding_manual_signin.xml

@ -2,7 +2,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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<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/onboarding_card"
@ -11,22 +12,51 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/avatar_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_onboarding_avatar_anonymous_large"
tools:ignore="RtlSymmetry" />
<TextView
android:id="@+id/header_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="14dp"
android:drawablePadding="12dp"
android:textAppearance="@style/Header16TextStyle"
android:lineSpacingExtra="8sp"
android:textColor="@color/neutral_text"
app:drawableTint="@color/white_color"
tools:text="@string/onboarding_firefox_account_header" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/avatar_icon"
android:layout_marginStart="52dp"
tools:text="@string/onboarding_firefox_account_header"
/>
<org.mozilla.fenix.utils.LinkTextView
android:id="@+id/learn_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/onboarding_manual_sign_in_learn_more"
android:textAppearance="@style/Header16TextStyle"
android:textColor="@color/neutral_text"
app:layout_constraintStart_toStartOf="@id/header_text"
app:layout_constraintTop_toBottomOf="@id/header_text"
tools:textColor="@color/neutral_text" />
<Button
style="@style/NeutralButton"
android:id="@+id/turn_on_sync_button"
android:id="@+id/fxa_sign_in_button"
android:background="@drawable/onboarding_padded_background"
android:layout_marginTop="10dp"
android:text="@string/onboarding_firefox_account_sign_in"
app:layout_constraintTop_toBottomOf="@id/learn_more"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="parent"
app:backgroundTint="@color/foundation_light_theme" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

7
app/src/main/res/values/strings.xml

@ -974,9 +974,10 @@
<string name="onboarding_whats_new_description">Have questions about the redesigned %s? Want to know what’s changed?</string>
<!-- text for underlined clickable link that is part of "what's new" onboarding card description that links to an FAQ -->
<string name="onboarding_whats_new_description_linktext">Get answers here</string>
<!-- text for the firefox account onboarding card header
The first parameter is the name of the app (e.g. Firefox Preview) -->
<string name="onboarding_firefox_account_header">Get the most out of %s.</string>
<!-- text for the firefox account onboarding card header -->
<string name="onboarding_firefox_account_header">Start syncing bookmarks, passwords, and more with your Firefox account.</string>
<!-- Text for the button to learn more about signing in to your Firefox account -->
<string name="onboarding_manual_sign_in_learn_more">Learn more</string>
<!-- text for the firefox account onboarding card header when we detect you're already signed in to
another Firefox browser. (The word `Firefox` should not be translated)
The first parameter is the email of the detected user's account -->

14
app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolderTest.kt

@ -65,7 +65,7 @@ class OnboardingAutomaticSignInViewHolderTest {
"You are signed in as email@example.com on another Firefox browser on this phone. Would you like to sign in with this account?",
view.header_text.text
)
assertTrue(view.turn_on_sync_button.isEnabled)
assertTrue(view.fxa_sign_in_button.isEnabled)
}
@Test
@ -79,10 +79,10 @@ class OnboardingAutomaticSignInViewHolderTest {
val holder = OnboardingAutomaticSignInViewHolder(view, scope = this)
holder.bind(account)
holder.onClick(view.turn_on_sync_button)
holder.onClick(view.fxa_sign_in_button)
assertEquals("Signing in…", view.turn_on_sync_button.text)
assertFalse(view.turn_on_sync_button.isEnabled)
assertEquals("Signing in…", view.fxa_sign_in_button.text)
assertFalse(view.fxa_sign_in_button.isEnabled)
}
@Test
@ -96,10 +96,10 @@ class OnboardingAutomaticSignInViewHolderTest {
val holder = OnboardingAutomaticSignInViewHolder(view, scope = this)
holder.bind(account)
holder.onClick(view.turn_on_sync_button)
holder.onClick(view.fxa_sign_in_button)
assertEquals("Yes, sign me in", view.turn_on_sync_button.text)
assertTrue(view.turn_on_sync_button.isEnabled)
assertEquals("Yes, sign me in", view.fxa_sign_in_button.text)
assertTrue(view.fxa_sign_in_button.isEnabled)
verify { snackbar.setText("Failed to sign-in") }
}
}

17
app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingManualSignInViewHolderTest.kt

@ -6,9 +6,12 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.NavController
import androidx.navigation.Navigation
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
@ -22,20 +25,27 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.HomeFragmentDirections
import org.mozilla.fenix.onboarding.OnboardingInteractor
@RunWith(FenixRobolectricTestRunner::class)
class OnboardingManualSignInViewHolderTest {
private lateinit var view: View
private lateinit var navController: NavController
private lateinit var interactor: OnboardingInteractor
private lateinit var itemView: ViewGroup
@Before
fun setup() {
view = LayoutInflater.from(testContext)
.inflate(OnboardingManualSignInViewHolder.LAYOUT_ID, null)
navController = mockk(relaxed = true)
interactor = mockk(relaxUnitFun = true)
itemView = mockk(relaxed = true)
mockkStatic(Navigation::class)
every { itemView.context } returns testContext
every { interactor.onLearnMoreClicked() } just Runs
every { Navigation.findNavController(view) } returns navController
}
@ -48,13 +58,16 @@ class OnboardingManualSignInViewHolderTest {
fun `bind header text`() {
OnboardingManualSignInViewHolder(view).bind()
assertEquals("Get the most out of Firefox Preview.", view.header_text.text)
assertEquals(
"Start syncing bookmarks, passwords, and more with your Firefox account.",
view.header_text.text
)
}
@Test
fun `navigate on click`() {
OnboardingManualSignInViewHolder(view)
view.turn_on_sync_button.performClick()
view.fxa_sign_in_button.performClick()
verify { navController.navigate(HomeFragmentDirections.actionGlobalTurnOnSync()) }
}

Loading…
Cancel
Save