Bug 1831068 - Incorporate Nimbus experiment 'lifestyle image' resources

fenix/115.2.0
t-p-white 1 year ago committed by mergify[bot]
parent 5af6180068
commit 481894e950

@ -81,6 +81,10 @@ objects:
description: The resource id of the image to be displayed. description: The resource id of the image to be displayed.
# This should never be defaulted. # This should never be defaulted.
default: ic_onboarding_welcome default: ic_onboarding_welcome
image-is-illustration:
type: Boolean
description: True if the image type is an illustration.
default: true
ordering: ordering:
type: Int type: Int
description: Used to sequence the cards. description: Used to sequence the cards.

@ -1,5 +1,6 @@
package org.mozilla.fenix.onboarding.view package org.mozilla.fenix.onboarding.view
import androidx.compose.ui.layout.ContentScale
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -31,6 +32,7 @@ class JunoOnboardingMapperTest {
private val defaultBrowserPageUiData = OnboardingPageUiData( private val defaultBrowserPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.DEFAULT_BROWSER, type = OnboardingPageUiData.Type.DEFAULT_BROWSER,
imageRes = R.drawable.ic_onboarding_welcome, imageRes = R.drawable.ic_onboarding_welcome,
imageResContentScale = ContentScale.Fit,
title = "default browser title", title = "default browser title",
description = "default browser body with link text", description = "default browser body with link text",
linkText = "link text", linkText = "link text",
@ -40,6 +42,7 @@ private val defaultBrowserPageUiData = OnboardingPageUiData(
private val syncPageUiData = OnboardingPageUiData( private val syncPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.SYNC_SIGN_IN, type = OnboardingPageUiData.Type.SYNC_SIGN_IN,
imageRes = R.drawable.ic_onboarding_sync, imageRes = R.drawable.ic_onboarding_sync,
imageResContentScale = ContentScale.Fit,
title = "sync title", title = "sync title",
description = "sync body", description = "sync body",
primaryButtonLabel = "sync primary button text", primaryButtonLabel = "sync primary button text",
@ -48,6 +51,7 @@ private val syncPageUiData = OnboardingPageUiData(
private val notificationPageUiData = OnboardingPageUiData( private val notificationPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION, type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION,
imageRes = R.drawable.ic_notification_permission, imageRes = R.drawable.ic_notification_permission,
imageResContentScale = ContentScale.Crop,
title = "notification title", title = "notification title",
description = "notification body", description = "notification body",
primaryButtonLabel = "notification primary button text", primaryButtonLabel = "notification primary button text",
@ -57,6 +61,7 @@ private val notificationPageUiData = OnboardingPageUiData(
private val defaultBrowserCardData = OnboardingCardData( private val defaultBrowserCardData = OnboardingCardData(
cardType = OnboardingCardType.DEFAULT_BROWSER, cardType = OnboardingCardType.DEFAULT_BROWSER,
imageRes = R.drawable.ic_onboarding_welcome, imageRes = R.drawable.ic_onboarding_welcome,
imageIsIllustration = true,
title = StringHolder(null, "default browser title"), title = StringHolder(null, "default browser title"),
body = StringHolder(null, "default browser body with link text"), body = StringHolder(null, "default browser body with link text"),
linkText = StringHolder(null, "link text"), linkText = StringHolder(null, "link text"),
@ -67,6 +72,7 @@ private val defaultBrowserCardData = OnboardingCardData(
private val syncCardData = OnboardingCardData( private val syncCardData = OnboardingCardData(
cardType = OnboardingCardType.SYNC_SIGN_IN, cardType = OnboardingCardType.SYNC_SIGN_IN,
imageRes = R.drawable.ic_onboarding_sync, imageRes = R.drawable.ic_onboarding_sync,
imageIsIllustration = true,
title = StringHolder(null, "sync title"), title = StringHolder(null, "sync title"),
body = StringHolder(null, "sync body"), body = StringHolder(null, "sync body"),
primaryButtonLabel = StringHolder(null, "sync primary button text"), primaryButtonLabel = StringHolder(null, "sync primary button text"),
@ -76,6 +82,7 @@ private val syncCardData = OnboardingCardData(
private val notificationCardData = OnboardingCardData( private val notificationCardData = OnboardingCardData(
cardType = OnboardingCardType.NOTIFICATION_PERMISSION, cardType = OnboardingCardType.NOTIFICATION_PERMISSION,
imageRes = R.drawable.ic_notification_permission, imageRes = R.drawable.ic_notification_permission,
imageIsIllustration = false,
title = StringHolder(null, "notification title"), title = StringHolder(null, "notification title"),
body = StringHolder(null, "notification body"), body = StringHolder(null, "notification body"),
primaryButtonLabel = StringHolder(null, "notification primary button text"), primaryButtonLabel = StringHolder(null, "notification primary button text"),

@ -82,3 +82,21 @@ fun Modifier.debouncedClickable(
), ),
) )
} }
/**
* A conditional [Modifier.then] extension that allows chaining of conditional Modifiers.
*
* @param modifier The [Modifier] to return if the [predicate] is satisfied.
* @param predicate The predicate used to determine which [Modifier] to return.
*
* @return the appropriate [Modifier] given the [predicate].
*/
fun Modifier.thenConditional(
modifier: Modifier,
predicate: () -> Boolean,
): Modifier =
if (predicate()) {
then(modifier)
} else {
this
}

@ -4,6 +4,7 @@
package org.mozilla.fenix.onboarding.view package org.mozilla.fenix.onboarding.view
import androidx.compose.ui.layout.ContentScale
import org.mozilla.fenix.nimbus.OnboardingCardData import org.mozilla.fenix.nimbus.OnboardingCardData
import org.mozilla.fenix.nimbus.OnboardingCardType import org.mozilla.fenix.nimbus.OnboardingCardType
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
@ -24,6 +25,7 @@ internal fun Collection<OnboardingCardData>.toPageUiData(showNotificationPage: B
private fun OnboardingCardData.toPageUiData() = OnboardingPageUiData( private fun OnboardingCardData.toPageUiData() = OnboardingPageUiData(
type = cardType.toPageUiDataType(), type = cardType.toPageUiDataType(),
imageRes = imageRes.resourceId, imageRes = imageRes.resourceId,
imageResContentScale = imageIsIllustration.toContentScale(),
title = title, title = title,
description = body, description = body,
linkText = linkText, linkText = linkText,
@ -31,6 +33,12 @@ private fun OnboardingCardData.toPageUiData() = OnboardingPageUiData(
secondaryButtonLabel = secondaryButtonLabel, secondaryButtonLabel = secondaryButtonLabel,
) )
private fun Boolean.toContentScale() = if (this) {
ContentScale.Fit
} else {
ContentScale.Crop
}
private fun OnboardingCardType.toPageUiDataType() = when (this) { private fun OnboardingCardType.toPageUiDataType() = when (this) {
OnboardingCardType.DEFAULT_BROWSER -> OnboardingPageUiData.Type.DEFAULT_BROWSER OnboardingCardType.DEFAULT_BROWSER -> OnboardingPageUiData.Type.DEFAULT_BROWSER
OnboardingCardType.SYNC_SIGN_IN -> OnboardingPageUiData.Type.SYNC_SIGN_IN OnboardingCardType.SYNC_SIGN_IN -> OnboardingPageUiData.Type.SYNC_SIGN_IN

@ -28,6 +28,7 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -173,7 +174,10 @@ private fun JunoOnboardingContent(
onNotificationPermissionButtonClick = onNotificationPermissionButtonClick, onNotificationPermissionButtonClick = onNotificationPermissionButtonClick,
onNotificationPermissionSkipClick = onNotificationPermissionSkipClick, onNotificationPermissionSkipClick = onNotificationPermissionSkipClick,
) )
OnboardingPage(pageState = onboardingPageState) OnboardingPage(
pageState = onboardingPageState,
imageResContentScale = pageUiState.imageResContentScale,
)
} }
PagerIndicator( PagerIndicator(
@ -233,6 +237,7 @@ private fun defaultPreviewPages() = listOf(
OnboardingPageUiData( OnboardingPageUiData(
type = OnboardingPageUiData.Type.DEFAULT_BROWSER, type = OnboardingPageUiData.Type.DEFAULT_BROWSER,
imageRes = R.drawable.ic_onboarding_welcome, imageRes = R.drawable.ic_onboarding_welcome,
imageResContentScale = ContentScale.Fit,
title = stringResource(R.string.juno_onboarding_default_browser_title_nimbus), title = stringResource(R.string.juno_onboarding_default_browser_title_nimbus),
description = stringResource(R.string.juno_onboarding_default_browser_description_nimbus), description = stringResource(R.string.juno_onboarding_default_browser_description_nimbus),
linkText = stringResource(R.string.juno_onboarding_default_browser_description_link_text), linkText = stringResource(R.string.juno_onboarding_default_browser_description_link_text),
@ -242,6 +247,7 @@ private fun defaultPreviewPages() = listOf(
OnboardingPageUiData( OnboardingPageUiData(
type = OnboardingPageUiData.Type.SYNC_SIGN_IN, type = OnboardingPageUiData.Type.SYNC_SIGN_IN,
imageRes = R.drawable.ic_onboarding_sync, imageRes = R.drawable.ic_onboarding_sync,
imageResContentScale = ContentScale.Fit,
title = stringResource(R.string.juno_onboarding_sign_in_title), title = stringResource(R.string.juno_onboarding_sign_in_title),
description = stringResource(R.string.juno_onboarding_sign_in_description), description = stringResource(R.string.juno_onboarding_sign_in_description),
primaryButtonLabel = stringResource(R.string.juno_onboarding_sign_in_positive_button), primaryButtonLabel = stringResource(R.string.juno_onboarding_sign_in_positive_button),
@ -250,6 +256,7 @@ private fun defaultPreviewPages() = listOf(
OnboardingPageUiData( OnboardingPageUiData(
type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION, type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION,
imageRes = R.drawable.ic_notification_permission, imageRes = R.drawable.ic_notification_permission,
imageResContentScale = ContentScale.Fit,
title = stringResource(R.string.juno_onboarding_enable_notifications_title_nimbus), title = stringResource(R.string.juno_onboarding_enable_notifications_title_nimbus),
description = stringResource(R.string.juno_onboarding_enable_notifications_description_nimbus), description = stringResource(R.string.juno_onboarding_enable_notifications_description_nimbus),
primaryButtonLabel = stringResource(R.string.juno_onboarding_enable_notifications_positive_button), primaryButtonLabel = stringResource(R.string.juno_onboarding_enable_notifications_positive_button),

@ -19,11 +19,14 @@ import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.IconButton import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
@ -36,6 +39,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.compose.annotation.LightDarkPreview
import org.mozilla.fenix.compose.button.PrimaryButton import org.mozilla.fenix.compose.button.PrimaryButton
import org.mozilla.fenix.compose.button.SecondaryButton import org.mozilla.fenix.compose.button.SecondaryButton
import org.mozilla.fenix.compose.ext.thenConditional
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
/** /**
@ -66,12 +70,15 @@ private const val URL_TAG = "URL_TAG"
* @param modifier The modifier to be applied to the Composable. * @param modifier The modifier to be applied to the Composable.
* @param onDismiss Invoked when the user clicks the close button. This defaults to null. When null, * @param onDismiss Invoked when the user clicks the close button. This defaults to null. When null,
* it doesn't show the close button. * it doesn't show the close button.
* @param imageResContentScale The [ContentScale] for the [OnboardingPageState.image].
*/ */
@Composable @Composable
@Suppress("LongMethod")
fun OnboardingPage( fun OnboardingPage(
pageState: OnboardingPageState, pageState: OnboardingPageState,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onDismiss: (() -> Unit)? = null, onDismiss: (() -> Unit)? = null,
imageResContentScale: ContentScale = ContentScale.Fit,
) { ) {
BoxWithConstraints( BoxWithConstraints(
modifier = Modifier modifier = Modifier
@ -109,7 +116,12 @@ fun OnboardingPage(
Image( Image(
painter = painterResource(id = pageState.image), painter = painterResource(id = pageState.image),
contentDescription = null, contentDescription = null,
modifier = Modifier.height(imageHeight(boxWithConstraintsScope)), contentScale = imageResContentScale,
modifier = Modifier
.height(imageHeight(boxWithConstraintsScope))
.thenConditional(Modifier.clip(MaterialTheme.shapes.medium)) {
imageResContentScale == ContentScale.Crop
},
) )
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))

@ -5,6 +5,7 @@
package org.mozilla.fenix.onboarding.view package org.mozilla.fenix.onboarding.view
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.ui.layout.ContentScale
import org.mozilla.fenix.nimbus.OnboardingCardData import org.mozilla.fenix.nimbus.OnboardingCardData
/** /**
@ -13,6 +14,7 @@ import org.mozilla.fenix.nimbus.OnboardingCardData
data class OnboardingPageUiData( data class OnboardingPageUiData(
val type: Type, val type: Type,
@DrawableRes val imageRes: Int, @DrawableRes val imageRes: Int,
val imageResContentScale: ContentScale,
val title: String, val title: String,
val description: String, val description: String,
val linkText: String? = null, val linkText: String? = null,

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/onboarding_default_browser,@drawable/onboarding_sync,@drawable/onboarding_notification" />

@ -0,0 +1,33 @@
/* 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.compose.ext
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.junit.Assert.assertEquals
import org.junit.Test
class ModifierTest {
@Test
fun `GIVEN predicate is false WHEN thenConditional called THEN the original modifier is returned`() {
val modifier = Modifier.height(1.dp)
assertEquals(modifier, modifier.thenConditional(Modifier.width(1.dp)) { false })
}
@Test
fun `GIVEN predicate is true WHEN thenConditional called THEN the updated modifier is returned`() {
val modifier = Modifier.height(1.dp)
val expected = Modifier
.height(1.dp)
.width(1.dp)
val actual = modifier.thenConditional(Modifier.width(1.dp)) { true }
assertEquals(expected, actual)
}
}

@ -4,6 +4,7 @@
package org.mozilla.fenix.onboarding.view package org.mozilla.fenix.onboarding.view
import androidx.compose.ui.layout.ContentScale
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -29,6 +30,7 @@ class JunoOnboardingMapperTest {
val onboardingPageUiData = OnboardingPageUiData( val onboardingPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.DEFAULT_BROWSER, type = OnboardingPageUiData.Type.DEFAULT_BROWSER,
imageRes = R.drawable.ic_onboarding_welcome, imageRes = R.drawable.ic_onboarding_welcome,
imageResContentScale = ContentScale.Fit,
title = "default browser title", title = "default browser title",
description = "default browser body with link text", description = "default browser body with link text",
linkText = "link text", linkText = "link text",
@ -62,6 +64,7 @@ class JunoOnboardingMapperTest {
val onboardingPageUiData = OnboardingPageUiData( val onboardingPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.SYNC_SIGN_IN, type = OnboardingPageUiData.Type.SYNC_SIGN_IN,
imageRes = R.drawable.ic_onboarding_sync, imageRes = R.drawable.ic_onboarding_sync,
imageResContentScale = ContentScale.Fit,
title = "sync title", title = "sync title",
description = "sync body", description = "sync body",
linkText = null, linkText = null,
@ -95,6 +98,7 @@ class JunoOnboardingMapperTest {
val onboardingPageUiData = OnboardingPageUiData( val onboardingPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION, type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION,
imageRes = R.drawable.ic_notification_permission, imageRes = R.drawable.ic_notification_permission,
imageResContentScale = ContentScale.Fit,
title = "notification title", title = "notification title",
description = "notification body", description = "notification body",
linkText = null, linkText = null,

@ -4,6 +4,7 @@
package org.mozilla.fenix.onboarding.view package org.mozilla.fenix.onboarding.view
import androidx.compose.ui.layout.ContentScale
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -54,6 +55,7 @@ class OnboardingPageUiDataTest {
private val defaultBrowserPageUiData = OnboardingPageUiData( private val defaultBrowserPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.DEFAULT_BROWSER, type = OnboardingPageUiData.Type.DEFAULT_BROWSER,
imageRes = R.drawable.ic_onboarding_welcome, imageRes = R.drawable.ic_onboarding_welcome,
imageResContentScale = ContentScale.Fit,
title = "default browser title", title = "default browser title",
description = "default browser body with link text", description = "default browser body with link text",
linkText = "link text", linkText = "link text",
@ -64,6 +66,7 @@ private val defaultBrowserPageUiData = OnboardingPageUiData(
private val syncPageUiData = OnboardingPageUiData( private val syncPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.SYNC_SIGN_IN, type = OnboardingPageUiData.Type.SYNC_SIGN_IN,
imageRes = R.drawable.ic_onboarding_sync, imageRes = R.drawable.ic_onboarding_sync,
imageResContentScale = ContentScale.Fit,
title = "sync title", title = "sync title",
description = "sync body", description = "sync body",
primaryButtonLabel = "sync primary button text", primaryButtonLabel = "sync primary button text",
@ -73,6 +76,7 @@ private val syncPageUiData = OnboardingPageUiData(
private val notificationPageUiData = OnboardingPageUiData( private val notificationPageUiData = OnboardingPageUiData(
type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION, type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION,
imageRes = R.drawable.ic_notification_permission, imageRes = R.drawable.ic_notification_permission,
imageResContentScale = ContentScale.Fit,
title = "notification title", title = "notification title",
description = "notification body", description = "notification body",
primaryButtonLabel = "notification primary button text", primaryButtonLabel = "notification primary button text",

Loading…
Cancel
Save