diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt index 385824799e..882c791eab 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/Buttons.kt @@ -114,6 +114,32 @@ fun PrimaryButtonIconEnd( ) } +/** + * [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=68%3A20&mode=design&t=YXX8vqJcB9jn0wPp-1) + * */ +@Composable +fun PrimaryButtonIconEndTwoLines( + text: String, + @DrawableRes iconResId: Int, + onClick: () -> Unit, + modifier: Modifier = Modifier, + showProgress: Boolean = false, + enabled: Boolean = true, + additionalText: String? = null, +) { + TangemButton( + modifier = modifier, + text = text, + icon = TangemButtonIconPosition.End(iconResId), + onClick = onClick, + colors = TangemButtonsDefaults.primaryButtonColors, + enabled = enabled, + showProgress = showProgress, + additionalText = additionalText, + size = TangemButtonSize.TwoLines, + ) +} + /** * [Show in Figma](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=233%3A258&t=TmfD6UBHPg9uYfev-4) * */ @@ -261,6 +287,13 @@ private fun PrimaryButtonSample() { enabled = false, onClick = { }, ) + PrimaryButtonIconEndTwoLines( + modifier = Modifier.fillMaxWidth(), + text = "Manage tokens", + iconResId = R.drawable.ic_tangem_24, + onClick = { }, + additionalText = "Manage these tokens", + ) PrimaryButtonIconStart( modifier = Modifier.fillMaxWidth(), text = "Manage tokens", diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt index fc114059fe..2d0d4b0b68 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButton.kt @@ -26,6 +26,7 @@ fun TangemButton( showProgress: Boolean, enabled: Boolean, modifier: Modifier = Modifier, + additionalText: String? = null, size: TangemButtonSize = TangemButtonSize.Default, elevation: ButtonElevation = TangemButtonsDefaults.elevation, textStyle: TextStyle = TangemTheme.typography.button, @@ -73,6 +74,20 @@ fun TangemButton( contentDescription = null, ) }, + additionalText = { + if (additionalText != null) { + Text( + modifier = Modifier + .fillMaxWidth(), + text = additionalText, + style = TangemTheme.typography.caption2, + color = TangemTheme.colors.text.disabled, + textAlign = TextAlign.Center, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + }, ) } } @@ -86,18 +101,27 @@ private inline fun RowScope.ButtonContentContainer( progressIndicator: @Composable RowScope.() -> Unit, text: @Composable RowScope.() -> Unit, icon: @Composable RowScope.(Int) -> Unit, + additionalText: @Composable () -> Unit, ) { if (showProgress) { progressIndicator() } else { - if (buttonIcon is TangemButtonIconPosition.Start) { - icon(buttonIcon.iconResId) - Spacer(modifier = Modifier.requiredWidth(iconPadding)) - } - text() - if (buttonIcon is TangemButtonIconPosition.End) { - Spacer(modifier = Modifier.requiredWidth(iconPadding)) - icon(buttonIcon.iconResId) + Column { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + if (buttonIcon is TangemButtonIconPosition.Start) { + icon(buttonIcon.iconResId) + Spacer(modifier = Modifier.requiredWidth(iconPadding)) + } + text() + if (buttonIcon is TangemButtonIconPosition.End) { + Spacer(modifier = Modifier.requiredWidth(iconPadding)) + icon(buttonIcon.iconResId) + } + } + additionalText() } } } diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt index e64aaf1965..09452682dc 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/buttons/common/TangemButtonSize.kt @@ -14,12 +14,13 @@ enum class TangemButtonSize { Selector, Action, RoundedAction, + TwoLines, } @Composable @ReadOnlyComposable internal fun TangemButtonSize.toHeightDp(): Dp = when (this) { - TangemButtonSize.Default -> TangemTheme.dimens.size48 + TangemButtonSize.Default, TangemButtonSize.TwoLines -> TangemTheme.dimens.size48 TangemButtonSize.Text -> TangemTheme.dimens.size40 TangemButtonSize.Selector -> TangemTheme.dimens.size24 TangemButtonSize.Action, @@ -34,13 +35,14 @@ internal fun TangemButtonSize.toShape(): Shape = when (this) { TangemButtonSize.Text -> TangemTheme.shapes.roundedCornersSmall TangemButtonSize.Selector -> TangemTheme.shapes.roundedCornersSmall TangemButtonSize.Action -> TangemTheme.shapes.roundedCornersMedium + TangemButtonSize.TwoLines -> TangemTheme.shapes.roundedCornersXMedium TangemButtonSize.RoundedAction -> TangemTheme.shapes.roundedCornersLarge } @Composable @ReadOnlyComposable internal fun TangemButtonSize.toIconPadding(): Dp = when (this) { - TangemButtonSize.Default -> TangemTheme.dimens.spacing4 + TangemButtonSize.Default, TangemButtonSize.TwoLines -> TangemTheme.dimens.spacing4 TangemButtonSize.Text -> TangemTheme.dimens.spacing8 TangemButtonSize.Selector -> 0.dp TangemButtonSize.Action, @@ -80,6 +82,12 @@ internal fun TangemButtonSize.toContentPadding(icon: TangemButtonIconPosition): start = horizontalPadding.first, end = horizontalPadding.second, ) + TangemButtonSize.TwoLines -> PaddingValues( + top = TangemTheme.dimens.spacing6, + bottom = TangemTheme.dimens.spacing6, + start = horizontalPadding.first, + end = horizontalPadding.second, + ) } } @@ -87,7 +95,8 @@ internal fun TangemButtonSize.toContentPadding(icon: TangemButtonIconPosition): @ReadOnlyComposable internal fun TangemButtonSize.toHorizontalContentPadding(icon: TangemButtonIconPosition): Pair { return when (this) { - TangemButtonSize.Default -> TangemTheme.dimens.spacing32 to TangemTheme.dimens.spacing32 + TangemButtonSize.Default, TangemButtonSize.TwoLines -> + TangemTheme.dimens.spacing32 to TangemTheme.dimens.spacing32 TangemButtonSize.Text -> when (icon) { is TangemButtonIconPosition.None -> TangemTheme.dimens.spacing16 to TangemTheme.dimens.spacing16 is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing14 to TangemTheme.dimens.spacing16 diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt index c5b35a183e..1992043a9e 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/NotificationConfig.kt @@ -28,6 +28,7 @@ data class NotificationConfig( data class PrimaryButtonConfig( val text: TextReference, + val additionalText: TextReference? = null, @DrawableRes val iconResId: Int? = null, val onClick: () -> Unit, ) : ButtonsState() diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt new file mode 100644 index 0000000000..addb35fc17 --- /dev/null +++ b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/DerivationNotificationState.kt @@ -0,0 +1,35 @@ +package com.tangem.managetokens.presentation.managetokens.state + +import com.tangem.core.ui.components.notifications.NotificationConfig +import com.tangem.core.ui.extensions.pluralReference +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.extensions.wrappedList +import com.tangem.features.managetokens.impl.R + +data class DerivationNotificationState( + val totalNeeded: Int, + val missingAddressesCount: Int, + val onGenerateClick: () -> Unit, +) { + val config = NotificationConfig( + title = resourceReference(id = R.string.warning_missing_derivation_title), + subtitle = pluralReference( + id = R.plurals.warning_missing_derivation_message, + count = totalNeeded, + formatArgs = wrappedList(totalNeeded), + ), + iconResId = R.drawable.ic_alert_circle_24, + buttonsState = NotificationConfig.ButtonsState.PrimaryButtonConfig( + text = resourceReference(id = R.string.common_generate_addresses), + iconResId = R.drawable.ic_tangem_24, + onClick = onGenerateClick, + // TODO: enable when we find how to use this type of strings with plurals on Localise + // Task: [REDACTED_JIRA] + // additionalText = pluralReference( + // id = R.plurals.manage_tokens_number_of_wallets, + // count = totalNeeded, + // formatArgs = wrappedList(missingAddressesCount, totalNeeded) + // ) + ), + ) +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt new file mode 100644 index 0000000000..207ea75cb8 --- /dev/null +++ b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/state/previewdata/DerivationNotificationStatePreviewData.kt @@ -0,0 +1,11 @@ +package com.tangem.managetokens.presentation.managetokens.state.previewdata + +import com.tangem.managetokens.presentation.managetokens.state.DerivationNotificationState + +object DerivationNotificationStatePreviewData { + val state = DerivationNotificationState( + totalNeeded = 3, + missingAddressesCount = 2, + onGenerateClick = {}, + ) +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt new file mode 100644 index 0000000000..a18fffaf56 --- /dev/null +++ b/features/manage-tokens/impl/src/main/java/com/tangem/managetokens/presentation/managetokens/ui/components/DerivationNotification.kt @@ -0,0 +1,143 @@ +package com.tangem.managetokens.presentation.managetokens.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Card +import androidx.compose.material.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import com.tangem.core.ui.components.PrimaryButtonIconEndTwoLines +import com.tangem.core.ui.components.SpacerW +import com.tangem.core.ui.components.notifications.NotificationConfig +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.managetokens.impl.R +import com.tangem.managetokens.presentation.managetokens.state.previewdata.DerivationNotificationStatePreviewData + +@Composable +internal fun DerivationNotification(config: NotificationConfig, modifier: Modifier = Modifier) { + BaseContainer( + modifier = modifier, + ) { + Column( + modifier = Modifier.padding(all = TangemTheme.dimens.spacing16), + verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing16), + ) { + MainContent( + iconResId = config.iconResId, + iconTint = TangemTheme.colors.icon.accent, + title = config.title, + subtitle = config.subtitle, + ) + val buttonConfig = config.buttonsState + if (buttonConfig is NotificationConfig.ButtonsState.PrimaryButtonConfig) { + PrimaryButtonIconEndTwoLines( + text = buttonConfig.text.resolveReference(), + iconResId = buttonConfig.iconResId ?: R.drawable.ic_tangem_24, + onClick = buttonConfig.onClick, + modifier = Modifier + .fillMaxWidth(), + additionalText = buttonConfig.additionalText?.resolveReference(), + ) + } + } + } +} + +@Composable +private fun BaseContainer(modifier: Modifier = Modifier, content: @Composable BoxScope.() -> Unit) { + Card( + modifier = modifier + .defaultMinSize(minHeight = TangemTheme.dimens.size62) + .fillMaxWidth(), + shape = RoundedCornerShape( + topStart = TangemTheme.dimens.radius16, + topEnd = TangemTheme.dimens.radius16, + ), + elevation = TangemTheme.dimens.elevation12, + backgroundColor = TangemTheme.colors.background.action, + ) { + Box(content = content) + } +} + +@Composable +private fun MainContent(iconResId: Int, iconTint: Color, title: TextReference, subtitle: TextReference) { + Row { + NotificationIcon(iconResId = iconResId, iconTint = iconTint) + SpacerW(width = TangemTheme.dimens.spacing10) + TextsBlock(title = title, subtitle = subtitle) + } +} + +@Composable +private fun RowScope.NotificationIcon(iconResId: Int, iconTint: Color) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .align(alignment = Alignment.CenterVertically), + ) { + Box( + modifier = Modifier + .size(TangemTheme.dimens.size36) + .background( + color = iconTint.copy(alpha = 0.12f), + shape = CircleShape, + ), + ) + Box( + modifier = Modifier + .size(TangemTheme.dimens.size16) + .background( + color = TangemTheme.colors.background.action, + shape = CircleShape, + ), + ) + Icon( + painter = painterResource(id = iconResId), + contentDescription = null, + tint = iconTint, + ) + } +} + +@Composable +private fun TextsBlock(title: TextReference, subtitle: TextReference) { + Column(verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing2)) { + Text( + text = title.resolveReference(), + color = TangemTheme.colors.text.primary1, + style = TangemTheme.typography.button, + ) + + Text( + text = subtitle.resolveReference(), + color = TangemTheme.colors.text.tertiary, + style = TangemTheme.typography.caption2, + ) + } +} + +@Preview +@Composable +private fun Preview_ManageTokensScreen_LightTheme() { + TangemTheme(isDark = false) { + DerivationNotification(DerivationNotificationStatePreviewData.state.config) + } +} + +@Preview +@Composable +private fun Preview_ManageTokensScreen_DarkTheme() { + TangemTheme(isDark = true) { + DerivationNotification(DerivationNotificationStatePreviewData.state.config) + } +} \ No newline at end of file