/* 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 import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row 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.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import org.mozilla.fenix.R import org.mozilla.fenix.compose.annotation.LightDarkPreview import org.mozilla.fenix.compose.button.PrimaryButton import org.mozilla.fenix.theme.FirefoxTheme /** * Message Card. * * @param messageText The message card's body text to be displayed. * @param titleText An optional title of message card. If the provided title text is blank or null, * the title will not be shown. * @param buttonText An optional button text of the message card. If the provided button text is blank or null, * the button won't be shown. * @param messageColors The color set defined by [MessageCardColors] used to style the message card. * @param onClick Invoked when user clicks on the message card. * @param onCloseButtonClick Invoked when user clicks on close button to remove message. */ @Suppress("LongMethod") @Composable fun MessageCard( messageText: String, titleText: String? = null, buttonText: String? = null, messageColors: MessageCardColors = MessageCardColors.buildMessageCardColors(), onClick: () -> Unit, onCloseButtonClick: () -> Unit, ) { Card( modifier = Modifier .padding(vertical = 16.dp) .then( if (buttonText.isNullOrBlank()) { Modifier.clickable(onClick = onClick) } else { Modifier }, ), shape = RoundedCornerShape(8.dp), backgroundColor = messageColors.backgroundColor, ) { Column( Modifier .padding(all = 16.dp) .fillMaxWidth(), ) { if (!titleText.isNullOrBlank()) { Row( modifier = Modifier.fillMaxWidth(), ) { Text( text = titleText, modifier = Modifier.weight(1f), color = messageColors.titleTextColor, overflow = TextOverflow.Ellipsis, maxLines = 2, style = FirefoxTheme.typography.headline7, ) MessageCardIconButton( iconTint = messageColors.iconColor, onCloseButtonClick = onCloseButtonClick, ) } Text( text = messageText, modifier = Modifier.fillMaxWidth(), fontSize = 14.sp, color = messageColors.messageTextColor, ) } else { Row( modifier = Modifier.fillMaxWidth(), ) { Text( text = messageText, modifier = Modifier.weight(1f), fontSize = 14.sp, color = messageColors.titleTextColor, ) MessageCardIconButton( iconTint = messageColors.iconColor, onCloseButtonClick = onCloseButtonClick, ) } } if (!buttonText.isNullOrBlank()) { Spacer(modifier = Modifier.height(16.dp)) PrimaryButton( text = buttonText, textColor = messageColors.buttonTextColor, backgroundColor = messageColors.buttonColor, onClick = onClick, ) } } } } /** * IconButton within a MessageCard. * * @param iconTint The [Color] used to tint the button's icon. * @param onCloseButtonClick Invoked when user clicks on close button to remove message. */ @Composable private fun MessageCardIconButton( iconTint: Color, onCloseButtonClick: () -> Unit, ) { IconButton( modifier = Modifier.size(20.dp), onClick = onCloseButtonClick, ) { Icon( painter = painterResource(R.drawable.mozac_ic_close_20), contentDescription = stringResource( R.string.content_description_close_button, ), tint = iconTint, ) } } /** * Wrapper for the color parameters of [MessageCard]. * * @param backgroundColor The background [Color] of the message. * @param titleTextColor [Color] to apply to the message's title, or the body text when there is no title. * @param messageTextColor [Color] to apply to the message's body text. * @param iconColor [Color] to apply to the message's icon. * @param buttonColor The background [Color] of the message's button. * @param buttonTextColor [Color] to apply to the button text. */ data class MessageCardColors( val backgroundColor: Color, val titleTextColor: Color, val messageTextColor: Color, val iconColor: Color, val buttonColor: Color, val buttonTextColor: Color, ) { companion object { /** * Builder function used to construct an instance of [MessageCardColors]. */ @Composable fun buildMessageCardColors( backgroundColor: Color = FirefoxTheme.colors.layer2, titleTextColor: Color = FirefoxTheme.colors.textPrimary, messageTextColor: Color = FirefoxTheme.colors.textSecondary, iconColor: Color = FirefoxTheme.colors.iconPrimary, buttonColor: Color = FirefoxTheme.colors.actionPrimary, buttonTextColor: Color = FirefoxTheme.colors.textActionPrimary, ): MessageCardColors = MessageCardColors( backgroundColor = backgroundColor, titleTextColor = titleTextColor, messageTextColor = messageTextColor, iconColor = iconColor, buttonColor = buttonColor, buttonTextColor = buttonTextColor, ) } } @Composable @LightDarkPreview private fun MessageCardPreview() { FirefoxTheme { Box( Modifier .background(FirefoxTheme.colors.layer1) .padding(all = 16.dp), ) { MessageCard( messageText = stringResource(id = R.string.default_browser_experiment_card_text), titleText = stringResource(id = R.string.bookmark_empty_title_error), onClick = {}, onCloseButtonClick = {}, ) } } } @Composable @LightDarkPreview private fun MessageCardWithoutTitlePreview() { FirefoxTheme { Box( modifier = Modifier .background(FirefoxTheme.colors.layer1) .padding(all = 16.dp), ) { MessageCard( messageText = stringResource(id = R.string.default_browser_experiment_card_text), onClick = {}, onCloseButtonClick = {}, ) } } } @Composable @LightDarkPreview private fun MessageCardWithButtonLabelPreview() { FirefoxTheme { Box( modifier = Modifier .background(FirefoxTheme.colors.layer1) .padding(all = 16.dp), ) { MessageCard( messageText = stringResource(id = R.string.default_browser_experiment_card_text), titleText = stringResource(id = R.string.bookmark_empty_title_error), buttonText = stringResource(id = R.string.preferences_set_as_default_browser), onClick = {}, onCloseButtonClick = {}, ) } } }