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
import android.content.res.Configuration
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
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.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
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.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.unit.dp
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.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.
*
* @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.
*/
@Composable
@ -44,42 +91,115 @@ fun PrimaryButton(
onClick: () -> Unit,
) {
Button(
text = text,
textColor = FirefoxTheme.colors.textActionPrimary,
backgroundColor = FirefoxTheme.colors.actionPrimary,
icon = icon,
tint = FirefoxTheme.colors.iconActionPrimary,
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,
color = FirefoxTheme.colors.textOnColorPrimary,
fontSize = 14.sp,
fontFamily = FontFamily(Font(R.font.metropolis_semibold)),
letterSpacing = 0.sp,
maxLines = 2
)
}
/**
* Tertiary 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 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
@Preview
private fun PrimaryButtonPreview() {
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun ButtonPreview() {
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(
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),
onClick = {},
)

View File

@ -20,17 +20,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
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.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
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.SecondaryText
import org.mozilla.fenix.compose.ThumbnailCard
import org.mozilla.fenix.compose.button.Button
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.theme.Theme
@ -134,30 +131,20 @@ fun RecentSyncedTab(
Spacer(modifier = Modifier.height(32.dp))
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,
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 androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
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.ui.Modifier
import androidx.compose.ui.platform.ComposeView
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.sp
import androidx.lifecycle.LifecycleOwner
import org.mozilla.fenix.R
import org.mozilla.fenix.compose.ComposeViewHolder
import org.mozilla.fenix.compose.button.TertiaryButton
import org.mozilla.fenix.home.sessioncontrol.CustomizeHomeIteractor
import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.theme.Theme
class CustomizeHomeButtonViewHolder(
composeView: ComposeView,
@ -40,56 +29,21 @@ class CustomizeHomeButtonViewHolder(
val LAYOUT_ID = View.generateViewId()
}
init {
val horizontalPadding =
composeView.resources.getDimensionPixelSize(R.dimen.home_item_horizontal_margin)
composeView.setPadding(horizontalPadding, 0, horizontalPadding, 0)
}
@Composable
override fun Content() {
Column {
Spacer(modifier = Modifier.height(68.dp))
CustomizeHomeButton(
onButtonClick = { interactor.openCustomizeHomePage() }
TertiaryButton(
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,
iconActionPrimary = PhotonColors.LightGrey05,
iconActionSecondary = PhotonColors.DarkGrey90,
iconActionTertiary = PhotonColors.LightGrey05,
iconGradientStart = PhotonColors.Violet20,
iconGradientEnd = PhotonColors.Blue20,
borderPrimary = PhotonColors.DarkGrey05,
@ -197,6 +198,7 @@ private val darkColorPalette = FirefoxColors(
iconAccentYellow = PhotonColors.Yellow20,
iconActionPrimary = PhotonColors.LightGrey05,
iconActionSecondary = PhotonColors.DarkGrey90,
iconActionTertiary = PhotonColors.LightGrey05,
iconGradientStart = PhotonColors.Violet20,
iconGradientEnd = PhotonColors.Blue20,
borderPrimary = PhotonColors.DarkGrey05,
@ -262,6 +264,7 @@ private val lightColorPalette = FirefoxColors(
iconAccentYellow = PhotonColors.Yellow60,
iconActionPrimary = PhotonColors.LightGrey05,
iconActionSecondary = PhotonColors.DarkGrey90,
iconActionTertiary = PhotonColors.DarkGrey90,
iconGradientStart = PhotonColors.Violet50,
iconGradientEnd = PhotonColors.Blue60,
borderPrimary = PhotonColors.LightGrey30,
@ -332,6 +335,7 @@ class FirefoxColors(
iconAccentYellow: Color,
iconActionPrimary: Color,
iconActionSecondary: Color,
iconActionTertiary: Color,
iconGradientStart: Color,
iconGradientEnd: Color,
borderPrimary: Color,
@ -507,6 +511,9 @@ class FirefoxColors(
// Action secondary icon
var iconActionSecondary by mutableStateOf(iconActionSecondary)
private set
// Action tertiary icon
var iconActionTertiary by mutableStateOf(iconActionTertiary)
private set
// Reader, ETP Shield
var iconGradientStart by mutableStateOf(iconGradientStart)
private set
@ -590,6 +597,7 @@ class FirefoxColors(
iconAccentYellow = other.iconAccentYellow
iconActionPrimary = other.iconActionPrimary
iconActionSecondary = other.iconActionSecondary
iconActionTertiary = other.iconActionTertiary
iconGradientStart = other.iconGradientStart
iconGradientEnd = other.iconGradientEnd
borderPrimary = other.borderPrimary
@ -655,6 +663,7 @@ class FirefoxColors(
iconAccentYellow = iconAccentYellow,
iconActionPrimary = iconActionPrimary,
iconActionSecondary = iconActionSecondary,
iconActionTertiary = iconActionTertiary,
iconGradientStart = iconGradientStart,
iconGradientEnd = iconGradientEnd,
borderPrimary = borderPrimary,

View File

@ -107,6 +107,8 @@
<color name="fx_mobile_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Action Secondary Icon -->
<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 -->
<color name="fx_mobile_icon_color_gradient_start">@color/photonViolet20</color>
<!-- Reader, ETP Shield -->

View File

@ -107,6 +107,8 @@
<color name="fx_mobile_icon_color_action_primary" tools:ignore="UnusedResources">@color/photonLightGrey05</color>
<!-- Action Secondary Icon -->
<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 -->
<color name="fx_mobile_icon_color_gradient_start">@color/photonViolet50</color>
<!-- 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_green" tools:ignore="UnusedResources">@color/photonGreen20</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 -->
<color name="fx_mobile_private_icon_color_gradient_start" tools:ignore="UnusedResources">@color/photonViolet20</color>
<!-- Reader, ETP Shield -->