For #25119 - Add Secondary, Tertiary and Destructive Button composable components

This commit is contained in:
Gabriel Luong 2022-05-04 22:54:34 -04:00 committed by mergify[bot]
parent 882494ccfb
commit 9a965e420d
6 changed files with 199 additions and 119 deletions

View File

@ -4,25 +4,23 @@
package org.mozilla.fenix.compose.button package org.mozilla.fenix.compose.button
import android.content.res.Configuration
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@ -30,11 +28,60 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.theme.Theme import org.mozilla.fenix.theme.Theme
/**
* Base component for buttons.
*
* @param text The button text to be displayed.
* @param textColor [Color] to apply to the button text.
* @param backgroundColor The background [Color] of the button.
* @param icon Optional [Painter] used to display a [Icon] before the button text.
* @param tint Tint [Color] to be applied to the icon.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun Button(
text: String,
textColor: Color,
backgroundColor: Color,
icon: Painter? = null,
tint: Color,
onClick: () -> Unit,
) {
androidx.compose.material.Button(
onClick = onClick,
modifier = Modifier
.fillMaxWidth()
.height(36.dp),
elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, pressedElevation = 0.dp),
colors = ButtonDefaults.outlinedButtonColors(
backgroundColor = backgroundColor,
),
) {
icon?.let { painter ->
Icon(
painter = painter,
contentDescription = null,
tint = tint,
)
Spacer(modifier = Modifier.width(8.dp))
}
Text(
text = text,
color = textColor,
fontSize = 14.sp,
letterSpacing = 0.25.sp,
maxLines = 1,
)
}
}
/** /**
* Primary button. * Primary button.
* *
* @param text The button text to be displayed. * @param text The button text to be displayed.
* @param icon Optional button icon to be displayed. * @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param onClick Invoked when the user clicks on the button. * @param onClick Invoked when the user clicks on the button.
*/ */
@Composable @Composable
@ -44,42 +91,115 @@ fun PrimaryButton(
onClick: () -> Unit, onClick: () -> Unit,
) { ) {
Button( Button(
text = text,
textColor = FirefoxTheme.colors.textActionPrimary,
backgroundColor = FirefoxTheme.colors.actionPrimary,
icon = icon,
tint = FirefoxTheme.colors.iconActionPrimary,
onClick = onClick, onClick = onClick,
modifier = Modifier )
.clip(RoundedCornerShape(size = 4.dp)) }
.fillMaxWidth()
.height(36.dp),
elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, pressedElevation = 0.dp),
colors = ButtonDefaults.outlinedButtonColors(backgroundColor = FirefoxTheme.colors.actionPrimary),
) {
if (icon != null) {
Icon(
painter = icon,
contentDescription = null,
tint = FirefoxTheme.colors.iconOnColor,
)
Spacer(modifier = Modifier.width(8.dp)) /**
} * Secondary button.
*
* @param text The button text to be displayed.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun SecondaryButton(
text: String,
icon: Painter? = null,
onClick: () -> Unit,
) {
Button(
text = text,
textColor = FirefoxTheme.colors.textActionSecondary,
backgroundColor = FirefoxTheme.colors.actionSecondary,
icon = icon,
tint = FirefoxTheme.colors.iconActionSecondary,
onClick = onClick,
)
}
Text( /**
text = text, * Tertiary button.
color = FirefoxTheme.colors.textOnColorPrimary, *
fontSize = 14.sp, * @param text The button text to be displayed.
fontFamily = FontFamily(Font(R.font.metropolis_semibold)), * @param icon Optional [Painter] used to display an [Icon] before the button text.
letterSpacing = 0.sp, * @param onClick Invoked when the user clicks on the button.
maxLines = 2 */
) @Composable
} fun TertiaryButton(
text: String,
icon: Painter? = null,
onClick: () -> Unit,
) {
Button(
text = text,
textColor = FirefoxTheme.colors.textActionTertiary,
backgroundColor = FirefoxTheme.colors.actionTertiary,
icon = icon,
tint = FirefoxTheme.colors.iconActionTertiary,
onClick = onClick,
)
}
/**
* Destructive button.
*
* @param text The button text to be displayed.
* @param icon Optional [Painter] used to display an [Icon] before the button text.
* @param onClick Invoked when the user clicks on the button.
*/
@Composable
fun DestructiveButton(
text: String,
icon: Painter? = null,
onClick: () -> Unit,
) {
Button(
text = text,
textColor = FirefoxTheme.colors.textWarningButton,
backgroundColor = FirefoxTheme.colors.actionSecondary,
icon = icon,
tint = FirefoxTheme.colors.iconWarningButton,
onClick = onClick,
)
} }
@Composable @Composable
@Preview @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun PrimaryButtonPreview() { @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun ButtonPreview() {
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) { FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
Box(Modifier.background(FirefoxTheme.colors.layer1)) { Column(
modifier = Modifier
.background(FirefoxTheme.colors.layer1)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
PrimaryButton( PrimaryButton(
text = stringResource(R.string.recent_tabs_show_all), text = "Label",
icon = painterResource(R.drawable.ic_tab_collection),
onClick = {},
)
SecondaryButton(
text = "Label",
icon = painterResource(R.drawable.ic_tab_collection),
onClick = {},
)
TertiaryButton(
text = "Label",
icon = painterResource(R.drawable.ic_tab_collection),
onClick = {},
)
DestructiveButton(
text = "Label",
icon = painterResource(R.drawable.ic_tab_collection), icon = painterResource(R.drawable.ic_tab_collection),
onClick = {}, onClick = {},
) )

View File

@ -20,17 +20,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.draw.clip
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.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -40,6 +36,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.compose.PrimaryText import org.mozilla.fenix.compose.PrimaryText
import org.mozilla.fenix.compose.SecondaryText import org.mozilla.fenix.compose.SecondaryText
import org.mozilla.fenix.compose.ThumbnailCard import org.mozilla.fenix.compose.ThumbnailCard
import org.mozilla.fenix.compose.button.Button
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.theme.Theme import org.mozilla.fenix.theme.Theme
@ -134,30 +131,20 @@ fun RecentSyncedTab(
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
Button( Button(
text = if (tab != null) {
stringResource(R.string.recent_tabs_see_all_synced_tabs_button_text)
} else {
""
},
textColor = FirefoxTheme.colors.textActionSecondary,
backgroundColor = if (tab == null) {
FirefoxTheme.colors.layer3
} else {
FirefoxTheme.colors.actionSecondary
},
tint = FirefoxTheme.colors.iconActionSecondary,
onClick = onSeeAllSyncedTabsButtonClick, onClick = onSeeAllSyncedTabsButtonClick,
colors = ButtonDefaults.outlinedButtonColors( )
backgroundColor = if (tab == null) {
FirefoxTheme.colors.layer3
} else {
FirefoxTheme.colors.actionSecondary
}
),
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp
),
modifier = Modifier
.height(36.dp)
.fillMaxWidth()
) {
if (tab != null) {
Text(
text = stringResource(R.string.recent_tabs_see_all_synced_tabs_button_text),
textAlign = TextAlign.Center,
color = FirefoxTheme.colors.textActionSecondary
)
}
}
} }
} }
} }

View File

@ -7,28 +7,17 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders
import android.view.View import android.view.View
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ButtonDefaults.outlinedButtonColors
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.compose.ComposeViewHolder
import org.mozilla.fenix.compose.button.TertiaryButton
import org.mozilla.fenix.home.sessioncontrol.CustomizeHomeIteractor import org.mozilla.fenix.home.sessioncontrol.CustomizeHomeIteractor
import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.theme.Theme
class CustomizeHomeButtonViewHolder( class CustomizeHomeButtonViewHolder(
composeView: ComposeView, composeView: ComposeView,
@ -40,56 +29,21 @@ class CustomizeHomeButtonViewHolder(
val LAYOUT_ID = View.generateViewId() val LAYOUT_ID = View.generateViewId()
} }
init {
val horizontalPadding =
composeView.resources.getDimensionPixelSize(R.dimen.home_item_horizontal_margin)
composeView.setPadding(horizontalPadding, 0, horizontalPadding, 0)
}
@Composable @Composable
override fun Content() { override fun Content() {
Column { Column {
Spacer(modifier = Modifier.height(68.dp)) Spacer(modifier = Modifier.height(68.dp))
CustomizeHomeButton( TertiaryButton(
onButtonClick = { interactor.openCustomizeHomePage() } text = stringResource(R.string.browser_menu_customize_home_1),
onClick = interactor::openCustomizeHomePage,
) )
} }
} }
} }
/**
* A "Customize homepage" button.
*
* @param onButtonClick Invoked when the user clicks on the button.
*/
@Composable
fun CustomizeHomeButton(
onButtonClick: () -> Unit
) {
Button(
onClick = { onButtonClick() },
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth()
.height(36.dp),
elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, pressedElevation = 0.dp),
colors = outlinedButtonColors(
backgroundColor = FirefoxTheme.colors.actionTertiary,
contentColor = FirefoxTheme.colors.textActionTertiary
)
) {
Text(
text = stringResource(R.string.browser_menu_customize_home_1),
fontSize = 14.sp,
fontFamily = FontFamily(Font(R.font.metropolis_semibold)),
letterSpacing = 0.5.sp,
lineHeight = 16.sp,
maxLines = 1
)
}
}
@Composable
@Preview
fun CustomizeHomeButtonPreview() {
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
CustomizeHomeButton(
onButtonClick = {}
)
}
}

View File

@ -132,6 +132,7 @@ private val privateColorPalette = FirefoxColors(
iconAccentYellow = PhotonColors.Yellow20, iconAccentYellow = PhotonColors.Yellow20,
iconActionPrimary = PhotonColors.LightGrey05, iconActionPrimary = PhotonColors.LightGrey05,
iconActionSecondary = PhotonColors.DarkGrey90, iconActionSecondary = PhotonColors.DarkGrey90,
iconActionTertiary = PhotonColors.LightGrey05,
iconGradientStart = PhotonColors.Violet20, iconGradientStart = PhotonColors.Violet20,
iconGradientEnd = PhotonColors.Blue20, iconGradientEnd = PhotonColors.Blue20,
borderPrimary = PhotonColors.DarkGrey05, borderPrimary = PhotonColors.DarkGrey05,
@ -197,6 +198,7 @@ private val darkColorPalette = FirefoxColors(
iconAccentYellow = PhotonColors.Yellow20, iconAccentYellow = PhotonColors.Yellow20,
iconActionPrimary = PhotonColors.LightGrey05, iconActionPrimary = PhotonColors.LightGrey05,
iconActionSecondary = PhotonColors.DarkGrey90, iconActionSecondary = PhotonColors.DarkGrey90,
iconActionTertiary = PhotonColors.LightGrey05,
iconGradientStart = PhotonColors.Violet20, iconGradientStart = PhotonColors.Violet20,
iconGradientEnd = PhotonColors.Blue20, iconGradientEnd = PhotonColors.Blue20,
borderPrimary = PhotonColors.DarkGrey05, borderPrimary = PhotonColors.DarkGrey05,
@ -262,6 +264,7 @@ private val lightColorPalette = FirefoxColors(
iconAccentYellow = PhotonColors.Yellow60, iconAccentYellow = PhotonColors.Yellow60,
iconActionPrimary = PhotonColors.LightGrey05, iconActionPrimary = PhotonColors.LightGrey05,
iconActionSecondary = PhotonColors.DarkGrey90, iconActionSecondary = PhotonColors.DarkGrey90,
iconActionTertiary = PhotonColors.DarkGrey90,
iconGradientStart = PhotonColors.Violet50, iconGradientStart = PhotonColors.Violet50,
iconGradientEnd = PhotonColors.Blue60, iconGradientEnd = PhotonColors.Blue60,
borderPrimary = PhotonColors.LightGrey30, borderPrimary = PhotonColors.LightGrey30,
@ -332,6 +335,7 @@ class FirefoxColors(
iconAccentYellow: Color, iconAccentYellow: Color,
iconActionPrimary: Color, iconActionPrimary: Color,
iconActionSecondary: Color, iconActionSecondary: Color,
iconActionTertiary: Color,
iconGradientStart: Color, iconGradientStart: Color,
iconGradientEnd: Color, iconGradientEnd: Color,
borderPrimary: Color, borderPrimary: Color,
@ -507,6 +511,9 @@ class FirefoxColors(
// Action secondary icon // Action secondary icon
var iconActionSecondary by mutableStateOf(iconActionSecondary) var iconActionSecondary by mutableStateOf(iconActionSecondary)
private set private set
// Action tertiary icon
var iconActionTertiary by mutableStateOf(iconActionTertiary)
private set
// Reader, ETP Shield // Reader, ETP Shield
var iconGradientStart by mutableStateOf(iconGradientStart) var iconGradientStart by mutableStateOf(iconGradientStart)
private set private set
@ -590,6 +597,7 @@ class FirefoxColors(
iconAccentYellow = other.iconAccentYellow iconAccentYellow = other.iconAccentYellow
iconActionPrimary = other.iconActionPrimary iconActionPrimary = other.iconActionPrimary
iconActionSecondary = other.iconActionSecondary iconActionSecondary = other.iconActionSecondary
iconActionTertiary = other.iconActionTertiary
iconGradientStart = other.iconGradientStart iconGradientStart = other.iconGradientStart
iconGradientEnd = other.iconGradientEnd iconGradientEnd = other.iconGradientEnd
borderPrimary = other.borderPrimary borderPrimary = other.borderPrimary
@ -655,6 +663,7 @@ class FirefoxColors(
iconAccentYellow = iconAccentYellow, iconAccentYellow = iconAccentYellow,
iconActionPrimary = iconActionPrimary, iconActionPrimary = iconActionPrimary,
iconActionSecondary = iconActionSecondary, iconActionSecondary = iconActionSecondary,
iconActionTertiary = iconActionTertiary,
iconGradientStart = iconGradientStart, iconGradientStart = iconGradientStart,
iconGradientEnd = iconGradientEnd, iconGradientEnd = iconGradientEnd,
borderPrimary = borderPrimary, borderPrimary = borderPrimary,

View File

@ -107,6 +107,8 @@
<color name="fx_mobile_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color> <color name="fx_mobile_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Action Secondary Icon --> <!-- Action Secondary Icon -->
<color name="fx_mobile_icon_color_action_secondary">@color/photonDarkGrey90</color> <color name="fx_mobile_icon_color_action_secondary">@color/photonDarkGrey90</color>
<!-- Action Tertiary Icon -->
<color name="fx_mobile_icon_color_action_tertiary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Reader, ETP Shield --> <!-- Reader, ETP Shield -->
<color name="fx_mobile_icon_color_gradient_start">@color/photonViolet20</color> <color name="fx_mobile_icon_color_gradient_start">@color/photonViolet20</color>
<!-- Reader, ETP Shield --> <!-- Reader, ETP Shield -->

View File

@ -107,6 +107,8 @@
<color name="fx_mobile_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color> <color name="fx_mobile_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Action Secondary Icon --> <!-- Action Secondary Icon -->
<color name="fx_mobile_icon_color_action_secondary">@color/photonDarkGrey90</color> <color name="fx_mobile_icon_color_action_secondary">@color/photonDarkGrey90</color>
<!-- Action Tertiary Icon -->
<color name="fx_mobile_icon_color_action_tertiary" tools:ignore="UnusedResources">@color/photonDarkGrey90</color>
<!-- Reader, ETP Shield --> <!-- Reader, ETP Shield -->
<color name="fx_mobile_icon_color_gradient_start">@color/photonViolet50</color> <color name="fx_mobile_icon_color_gradient_start">@color/photonViolet50</color>
<!-- Reader, ETP Shield --> <!-- Reader, ETP Shield -->
@ -232,6 +234,12 @@
<color name="fx_mobile_private_icon_color_accent_pink" tools:ignore="UnusedResources">@color/photonPink20</color> <color name="fx_mobile_private_icon_color_accent_pink" tools:ignore="UnusedResources">@color/photonPink20</color>
<color name="fx_mobile_private_icon_color_accent_green" tools:ignore="UnusedResources">@color/photonGreen20</color> <color name="fx_mobile_private_icon_color_accent_green" tools:ignore="UnusedResources">@color/photonGreen20</color>
<color name="fx_mobile_private_icon_color_accent_yellow" tools:ignore="UnusedResources">@color/photonYellow20</color> <color name="fx_mobile_private_icon_color_accent_yellow" tools:ignore="UnusedResources">@color/photonYellow20</color>
<!-- Action Primary Icon -->
<color name="fx_mobile_private_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Action Secondary Icon -->
<color name="fx_mobile_private_icon_color_action_secondary" tools:ignore="UnusedResources">@color/photonDarkGrey90</color>
<!-- Action Tertiary Icon -->
<color name="fx_mobile_private_icon_color_action_tertiary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Reader, ETP Shield --> <!-- Reader, ETP Shield -->
<color name="fx_mobile_private_icon_color_gradient_start" tools:ignore="UnusedResources">@color/photonViolet20</color> <color name="fx_mobile_private_icon_color_gradient_start" tools:ignore="UnusedResources">@color/photonViolet20</color>
<!-- Reader, ETP Shield --> <!-- Reader, ETP Shield -->