diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/CopiedTextSnackbar.kt b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/CopiedTextSnackbar.kt new file mode 100644 index 0000000000..35cc8f6903 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/CopiedTextSnackbar.kt @@ -0,0 +1,114 @@ +package com.tangem.core.ui.components.snackbar + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Icon +import androidx.compose.material3.SnackbarData +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider +import com.tangem.core.ui.R +import com.tangem.core.ui.extensions.TextReference +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.res.TangemTheme + +/** + * Snackbar to inform the user about copying text to the clipboard + * + * @param message message + * @param modifier modifier + * + * @see Figma + * +[REDACTED_AUTHOR] + */ +@Composable +fun CopiedTextSnackbar(message: TextReference, modifier: Modifier = Modifier) { + BaseSnackbar(message = message, modifier = modifier) +} + +/** + * Snackbar to inform the user about copying text to the clipboard. + * + * @param snackbarData this is needed to better support Material3.SnackbarHost, but only supports the message field + * @param modifier modifier + * + * @see Figma + * +[REDACTED_AUTHOR] + */ +@Composable +fun CopiedTextSnackbar(snackbarData: SnackbarData, modifier: Modifier = Modifier) { + BaseSnackbar(message = stringReference(snackbarData.visuals.message), modifier = modifier) +} + +@Composable +private fun BaseSnackbar(message: TextReference, modifier: Modifier = Modifier) { + Row( + modifier = modifier + .background(color = TangemTheme.colors.icon.secondary, shape = TangemTheme.shapes.roundedCorners8) + .heightIn(min = TangemTheme.dimens.size48) + .padding( + horizontal = TangemTheme.dimens.spacing16, + vertical = TangemTheme.dimens.spacing14, + ), + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8), + verticalAlignment = Alignment.CenterVertically, + ) { + MarkIcon() + + MessageText(text = message, modifier = Modifier.weight(weight = 1f, fill = false)) + } +} + +@Composable +private fun MarkIcon() { + Icon( + painter = painterResource(id = R.drawable.ic_check_24), + contentDescription = null, + modifier = Modifier.size(TangemTheme.dimens.size20), + tint = TangemTheme.colors.icon.accent, + ) +} + +@Composable +private fun MessageText(text: TextReference, modifier: Modifier = Modifier) { + Text( + text = text.resolveReference(), + modifier = modifier, + color = TangemTheme.colors.text.disabled, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = TangemTheme.typography.body2, + ) +} + +@Preview(widthDp = 344, showBackground = true, fontScale = 1f) +@Preview(widthDp = 344, showBackground = true, fontScale = 1f, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(widthDp = 344, showBackground = true, fontScale = 2f) +@Composable +private fun Preview_CopiedTextSnackbar( + @PreviewParameter(CopiedTextSnackbarDataProvider::class) message: TextReference, +) { + TangemTheme(isDark = false) { + CopiedTextSnackbar(message = message) + } +} + +private class CopiedTextSnackbarDataProvider : CollectionPreviewParameterProvider( + collection = listOf( + stringReference(value = "Copied!"), + stringReference(value = "Contract address copied!"), + stringReference(value = "Coooooooooooontract addreeeeeeeeeeeeeeeess coooooooooooooooopied!"), + ), +) \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/CopiedTextSnackbarHost.kt b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/CopiedTextSnackbarHost.kt new file mode 100644 index 0000000000..3cff3dd5c0 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/CopiedTextSnackbarHost.kt @@ -0,0 +1,25 @@ +package com.tangem.core.ui.components.snackbar + +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +/** + * SnackbarHost to inform the user about copying text to the clipboard + * Based on Material3 component. It's best way to show [CopiedTextSnackbar]. + * + * @param hostState snackbar host state + * @param modifier modifier + * + * @see Figma + * +[REDACTED_AUTHOR] + */ +@Composable +fun CopiedTextSnackbarHost(hostState: SnackbarHostState, modifier: Modifier = Modifier) { + SnackbarHost(hostState = hostState, modifier = modifier) { + CopiedTextSnackbar(snackbarData = it) + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbar.kt b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbar.kt new file mode 100644 index 0000000000..70cacc3a82 --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbar.kt @@ -0,0 +1,84 @@ +package com.tangem.core.ui.components.snackbar + +import android.content.res.Configuration +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +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.tooling.preview.PreviewParameter +import com.tangem.core.ui.res.TangemTheme +import com.tangem.core.ui.res.TangemThemePreview + +/** + * Tangem snackbar. + * Based on Material3 component. It can be presented as one line or multi lines snackbar – depends on text length. + * + * @param data snackbar data + * @param modifier modifier + * @param actionOnNewLine flag that indicates if the action should be displayed on a new line (default: false) + * + * @see Figma + * +[REDACTED_AUTHOR] + */ +@Composable +fun TangemSnackbar(data: SnackbarData, modifier: Modifier = Modifier, actionOnNewLine: Boolean = false) { + Snackbar( + modifier = modifier, + action = { + ActionButton(label = data.visuals.actionLabel, onClick = data::performAction) + }, + actionOnNewLine = actionOnNewLine, + shape = TangemTheme.shapes.roundedCorners8, + containerColor = TangemTheme.colors.icon.secondary, + ) { + MessageText(text = data.visuals.message) + } +} + +@Composable +private fun ActionButton(label: String?, onClick: () -> Unit) { + if (!label.isNullOrBlank()) { + TextButton( + onClick = onClick, + colors = ButtonDefaults.textButtonColors( + contentColor = TangemTheme.colors.text.primary2, + ), + content = { + Text( + text = label, + maxLines = 1, + style = TangemTheme.typography.button, + ) + }, + ) + } +} + +@Composable +private fun MessageText(text: String) { + Text( + text = text, + color = TangemTheme.colors.text.disabled, + textAlign = TextAlign.Start, + overflow = TextOverflow.Ellipsis, + style = TangemTheme.typography.body2, + ) +} + +/** + * IMPORTANT! + * Preview doesn't work correctly, check on device or start [TangemSnackbarHost]'s preview in interactive mode * + */ +@Preview(widthDp = 344, showBackground = true, fontScale = 1f) +@Preview(widthDp = 344, showBackground = true, fontScale = 1f, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(widthDp = 344, showBackground = true, fontScale = 2f) +@Composable +private fun Preview_TangemSnackbar(@PreviewParameter(TangemSnackbarModelProvider::class) model: TangemSnackbarModel) { + TangemThemePreview { + TangemSnackbar(data = model.snackbarData, actionOnNewLine = model.actionOnNewLine) + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbarHost.kt b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbarHost.kt new file mode 100644 index 0000000000..d1cd229f6d --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbarHost.kt @@ -0,0 +1,48 @@ +package com.tangem.core.ui.components.snackbar + +import android.content.res.Configuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import com.tangem.core.ui.res.TangemThemePreview + +/** + * Tangem snackbar host. + * Based on Material3 component. It's best way to show [TangemSnackbar]. + * + * @param hostState snackbar host state + * @param modifier modifier + * @param actionOnNewLine flag that indicates if the action should be displayed on a new line (default: false) + * + * @see Figma + * +[REDACTED_AUTHOR] + */ +@Composable +fun TangemSnackbarHost(hostState: SnackbarHostState, modifier: Modifier = Modifier, actionOnNewLine: Boolean = false) { + SnackbarHost(hostState = hostState, modifier = modifier) { data -> + TangemSnackbar(data = data, actionOnNewLine = actionOnNewLine) + } +} + +@Preview(widthDp = 344, showBackground = true, fontScale = 1f) +@Preview(widthDp = 344, showBackground = true, fontScale = 1f, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(widthDp = 344, showBackground = true, fontScale = 2f) +@Composable +private fun Preview_TangemSnackbar(@PreviewParameter(TangemSnackbarModelProvider::class) model: TangemSnackbarModel) { + TangemThemePreview { + val snackbarHostState = remember(::SnackbarHostState) + + TangemSnackbarHost(hostState = snackbarHostState, actionOnNewLine = model.actionOnNewLine) + + LaunchedEffect(key1 = null) { + snackbarHostState.showSnackbar(visuals = model.snackbarData.visuals) + } + } +} \ No newline at end of file diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbarModelProvider.kt b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbarModelProvider.kt new file mode 100644 index 0000000000..e2bdbf3ecf --- /dev/null +++ b/core/ui/src/main/java/com/tangem/core/ui/components/snackbar/TangemSnackbarModelProvider.kt @@ -0,0 +1,74 @@ +package com.tangem.core.ui.components.snackbar + +import androidx.compose.material3.SnackbarData +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarVisuals +import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider + +internal data class TangemSnackbarModel(val snackbarData: SnackbarData, val actionOnNewLine: Boolean) + +internal class TangemSnackbarModelProvider : CollectionPreviewParameterProvider( + listOf( + createTangemSnackbarModel( + message = "Single-line description.", + actionLabel = "Button", + actionOnNewLine = false, + ), + createTangemSnackbarModel( + message = "Very loooooooooooong single-line description.", + actionLabel = "Button", + actionOnNewLine = false, + ), + createTangemSnackbarModel( + message = "Single-line description.", + actionLabel = "Very looooooong button name", + actionOnNewLine = false, + ), + createTangemSnackbarModel( + message = "Single-line description.", + actionLabel = "Button", + actionOnNewLine = true, + ), + createTangemSnackbarModel( + message = "Very loooooooooooong single-line description.", + actionLabel = "Button", + actionOnNewLine = true, + ), + createTangemSnackbarModel( + message = "Single-line description.", + actionLabel = "Very looooooong button name", + actionOnNewLine = true, + ), + ), +) { + + companion object { + + fun createTangemSnackbarModel( + message: String, + actionLabel: String, + actionOnNewLine: Boolean, + ): TangemSnackbarModel { + return TangemSnackbarModel( + snackbarData = createSnackbarData(message, actionLabel), + actionOnNewLine = actionOnNewLine, + ) + } + + private fun createSnackbarData(message: String, actionLabel: String): SnackbarData { + return object : SnackbarData { + + override val visuals: SnackbarVisuals + get() = object : SnackbarVisuals { + override val message: String = message + override val actionLabel: String = actionLabel + override val duration: SnackbarDuration = SnackbarDuration.Short // Never-mind + override val withDismissAction: Boolean = false // Never-mind + } + + override fun dismiss() = Unit + override fun performAction() = Unit + } + } + } +} \ No newline at end of file