diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/Toast.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/Toast.kt index 26dc90b78..355db6d07 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/Toast.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/Toast.kt @@ -3,56 +3,98 @@ package com.atls.hyperion.ui.components.toast import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Snackbar import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.style.TextAlign import com.atls.hyperion.ui.components.toast.styles.appearance.ToastAppearance import com.atls.hyperion.ui.components.toast.styles.appearance.default import com.atls.hyperion.ui.components.toast.styles.shape.ToastShape import com.atls.hyperion.ui.components.toast.styles.shape.default +import com.atls.hyperion.ui.primitives.layout.row.Row +import com.atls.hyperion.ui.theme.tokens.layout.Weight @Composable fun Toast( hostState: SnackbarHostState, + modifier: Modifier = Modifier, appearance: ToastAppearance = ToastAppearance.default(), shape: ToastShape = ToastShape.default(), + leadingContent: (@Composable () -> Unit)? = null, + trailingContent: (@Composable () -> Unit)? = null ) { + var leadingWidthPx by remember { mutableStateOf(0) } + var trailingWidthPx by remember { mutableStateOf(0) } + val density = LocalDensity.current + Box( modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.BottomCenter ) { - SnackbarHost( - hostState = hostState - ) { data -> + SnackbarHost(hostState = hostState) { data -> Snackbar( - modifier = Modifier + modifier = modifier .border( BorderStroke(shape.borderStroke, appearance.borderColor), RoundedCornerShape(shape.cornerRadius) - ), + ) + .fillMaxWidth(), shape = RoundedCornerShape(shape.cornerRadius), containerColor = appearance.backgroundColor, contentColor = appearance.textColor, action = {} ) { - Text( - text = data.visuals.message, - style = shape.typography, - textAlign = TextAlign.Center, + BoxWithConstraints( modifier = Modifier .background(appearance.backgroundColor) - .padding(shape.paddings) - ) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .onGloballyPositioned { leadingWidthPx = it.size.width }, + contentAlignment = Alignment.CenterStart + ) { + leadingContent?.invoke() + } + + Spacer(Modifier.weight(Weight.full)) + + Box( + modifier = Modifier.onGloballyPositioned { trailingWidthPx = it.size.width }, + contentAlignment = Alignment.CenterEnd + ) { + trailingContent?.invoke() + } + } + + val horizontalPadding = with(density) { maxOf(leadingWidthPx, trailingWidthPx).toDp() } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(start = horizontalPadding, end = horizontalPadding), + contentAlignment = Alignment.Center + ) { + Text( + text = data.visuals.message, + style = shape.typography, + textAlign = TextAlign.Center, + color = appearance.textColor + ) + } + } } } } diff --git a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/stories/Component.kt b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/stories/Component.kt index cef77fd51..fe7cc38d9 100644 --- a/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/stories/Component.kt +++ b/mobile/kmp/ui/src/commonMain/kotlin/com/atls/hyperion/ui/components/toast/stories/Component.kt @@ -5,61 +5,89 @@ import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import com.atls.hyperion.storybook.shared.model.ComponentExample -import com.atls.hyperion.storybook.shared.ui.ComponentVariants import com.atls.hyperion.ui.components.toast.Toast -import com.atls.hyperion.ui.components.toast.styles.appearance.ToastAppearance -import com.atls.hyperion.ui.components.toast.styles.appearance.default -import com.atls.hyperion.ui.components.toast.styles.shape.ToastShape -import com.atls.hyperion.ui.components.toast.styles.shape.default -import com.atls.hyperion.ui.components.toast.styles.shape.rounded -import com.atls.hyperion.ui.components.toast.styles.shape.square +import com.atls.hyperion.ui.generated.resources.Res +import com.atls.hyperion.ui.generated.resources.chevron_left +import com.atls.hyperion.ui.primitives.icon.Icon +import com.atls.hyperion.ui.primitives.icon.IconSize +import com.atls.hyperion.ui.theme.tokens.colors.Colors import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.painterResource class ToastStories : ComponentExample { override val name: String = "Toast" @Composable override fun Content() { - val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() - var isVisible by remember { mutableStateOf(false) } - var toastText by remember { mutableStateOf("This is a toast message") } + val hostEmpty = remember { SnackbarHostState() } + val hostLeading = remember { SnackbarHostState() } + val hostTrailing = remember { SnackbarHostState() } + val hostBoth = remember { SnackbarHostState() } Column { - ComponentVariants( - name = "Toast", - appearances = listOf( - "Default" to { ToastAppearance.default() } - ), - shapes = listOf( - "Default" to { ToastShape.default() }, - "Rounded" to { ToastShape.rounded() }, - "Square" to { ToastShape.square() } - ) - ) { appearance: ToastAppearance, shape: ToastShape -> - Button( - onClick = { - scope.launch { - snackbarHostState.showSnackbar("toast") - } - } - ) { - Text("Show Toast") + Text("Empty Toast") + Button(onClick = { scope.launch { hostEmpty.showSnackbar("Empty toast") } }) { + Text("Show Empty Toast") + } + Toast(hostState = hostEmpty) + + Text("Leading Icon Toast") + Button(onClick = { scope.launch { hostLeading.showSnackbar("Leading icon") } }) { + Text("Show Leading Toast") + } + Toast( + hostState = hostLeading, + leadingContent = { + Icon( + icon = painterResource(Res.drawable.chevron_left), + color = Colors.Text.red, + size = IconSize.medium + ) + } + ) + + Text("Trailing Icon Toast") + Button(onClick = { scope.launch { hostTrailing.showSnackbar("Trailing icon") } }) { + Text("Show Trailing Toast") + } + Toast( + hostState = hostTrailing, + trailingContent = { + Icon( + icon = painterResource(Res.drawable.chevron_left), + color = Colors.Text.red, + size = IconSize.medium + ) } - Toast( - hostState = snackbarHostState, - shape = shape, - appearance = appearance - ) + ) + + Text("Both Icons Toast") + Button(onClick = { scope.launch { hostBoth.showSnackbar("Both icons") } }) { + Text("Show Both Toast") } + Toast( + hostState = hostBoth, + leadingContent = { + Icon( + icon = painterResource(Res.drawable.chevron_left), + color = Colors.Text.red, + size = IconSize.medium + ) + }, + trailingContent = { + Icon( + icon = painterResource(Res.drawable.chevron_left), + color = Colors.Text.red, + size = IconSize.medium + ) + } + ) } } }