Updated on 2026-08-14

This commit is contained in:
Tangem 2024-05-16 16:27:47 +08:00
parent 7e8b240f98
commit ce2567f096
5 changed files with 345 additions and 0 deletions

View file

@ -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 <a href = https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2001-728&t=kDzSZDx0m0sk4iYz-4
* >Figma</a>
*
[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 <a href = https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2001-728&t=kDzSZDx0m0sk4iYz-4
* >Figma</a>
*
[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<TextReference>(
collection = listOf(
stringReference(value = "Copied!"),
stringReference(value = "Contract address copied!"),
stringReference(value = "Coooooooooooontract addreeeeeeeeeeeeeeeess coooooooooooooooopied!"),
),
)

View file

@ -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 <a href = https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=2001-728&t=kDzSZDx0m0sk4iYz-4
* >Figma</a>
*
[REDACTED_AUTHOR]
*/
@Composable
fun CopiedTextSnackbarHost(hostState: SnackbarHostState, modifier: Modifier = Modifier) {
SnackbarHost(hostState = hostState, modifier = modifier) {
CopiedTextSnackbar(snackbarData = it)
}
}

View file

@ -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 <a href = https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=682-761&t=kDzSZDx0m0sk4iYz-4
* >Figma</a>
*
[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)
}
}

View file

@ -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 <a href = https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=682-761&t=kDzSZDx0m0sk4iYz-4
* >Figma</a>
*
[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)
}
}
}

View file

@ -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<TangemSnackbarModel>(
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
}
}
}
}