Layout to show the current time and a label at the top of the screen. If device has a round screen, then the time will be curved along the top edge of the screen, if rectangular - then the text and the time will be straight

Android
@Composable
public fun TimeText(
    modifier: Modifier = Modifier,
    timeSource: TimeSource = TimeTextDefaults.timeSource(timeFormat()),
    timeTextStyle: TextStyle = TimeTextDefaults.timeTextStyle(),
    contentPadding: PaddingValues = TimeTextDefaults.ContentPadding,
    startLinearContent: (@Composable () -> Unit)? = null,
    startCurvedContent: (CurvedScope.() -> Unit)? = null,
    endLinearContent: (@Composable () -> Unit)? = null,
    endCurvedContent: (CurvedScope.() -> Unit)? = null,
    textLinearSeparator: @Composable () -> Unit = { TextSeparator(textStyle = timeTextStyle) },
    textCurvedSeparator: CurvedScope.() -> Unit = {
        CurvedTextSeparator(curvedTextStyle = CurvedTextStyle(timeTextStyle))
    },
)

Parameters

modifier Current modifier.
timeSource TimeSource which retrieves the current time and formats it.
timeTextStyle Optional textStyle for the time text itself
contentPadding The spacing values between the container and the content
startLinearContent a slot before the time which is used only on Square screens
startCurvedContent a slot before the time which is used only on Round screens
endLinearContent a slot after the time which is used only on Square screens
endCurvedContent a slot after the time which is used only on Round screens
textLinearSeparator a separator slot which is used only on Square screens
textCurvedSeparator a separator slot which is used only on Round screens

Code Examples

TimeTextAnimation

@Composable
fun TimeTextAnimation() {
    var showState by remember { mutableStateOf(false) }
    val showTransition = updateTransition(showState)
    val time = 350
    val animatedColor by
        showTransition.animateColor(
            label = "animatedColor",
            transitionSpec = {
                tween(
                    time,
                    easing =
                        when {
                            false isTransitioningTo true ->
                                // Fade In
                                CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f)
                            else ->
                                // Fade Out
                                CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)
                        },
                )
            },
        ) { state ->
            when (state) {
                true -> Color.White
                false -> Color.Transparent
            }
        }
    val animateSize by
        showTransition.animateFloat(
            label = "animatedSize",
            transitionSpec = { tween(time, easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)) },
        ) { state ->
            when (state) {
                true -> 1f
                false -> 0f
            }
        }
    val text = "Long text to animate"
    val curvedSeparatorSweep = 10f
    val curvedTextSweep = 80f
    val curvedAnimatedSweep = animateSize * (curvedSeparatorSweep + curvedTextSweep)
    val curvedSeparatorGap = curvedAnimatedSweep.coerceAtMost(curvedSeparatorSweep) / 2f
    val linearSeparatorSize = 10.dp
    val linearTextSize = 70.dp
    val linearAnimatedSize = animateSize * (linearSeparatorSize + linearTextSize)
    val linearSeparatorGap = linearAnimatedSize.coerceAtMost(linearSeparatorSize) / 2f
    val textStyle =
        TimeTextDefaults.timeTextStyle().copy(fontWeight = FontWeight.Normal, color = animatedColor)
    Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        TimeText(
            // Curved
            textCurvedSeparator = {
                curvedColumn(modifier = CurvedModifier.angularSize(curvedSeparatorGap)) {}
                curvedText("·", style = CurvedTextStyle(textStyle))
                curvedColumn(modifier = CurvedModifier.angularSize(curvedSeparatorGap)) {}
            },
            startCurvedContent = {
                curvedRow(
                    modifier =
                        CurvedModifier.sizeIn(
                            maxSweepDegrees =
                                (curvedAnimatedSweep - curvedSeparatorSweep).coerceAtLeast(0f)
                        )
                ) {
                    curvedText(
                        text,
                        CurvedModifier.sizeIn(maxSweepDegrees = curvedTextSweep),
                        style = CurvedTextStyle(textStyle),
                        overflow = TextOverflow.Ellipsis,
                    )
                }
            },
            // Linear
            textLinearSeparator = {
                Spacer(modifier = Modifier.width(linearSeparatorGap))
                Text("·", style = textStyle)
                Spacer(modifier = Modifier.width(linearSeparatorGap))
            },
            startLinearContent = {
                Box(
                    modifier =
                        Modifier.clipToBounds()
                            .widthIn(
                                max = (linearAnimatedSize - linearSeparatorSize).coerceAtLeast(0.dp)
                            )
                ) {
                    Text(
                        text,
                        maxLines = 1,
                        style = textStyle,
                        modifier =
                            Modifier.wrapContentWidth(align = Alignment.Start, unbounded = true)
                                .widthIn(max = linearTextSize),
                        overflow = TextOverflow.Ellipsis,
                    )
                }
            },
        )
        Button(onClick = { showState = !showState }) { Text("Go!") }
    }
}

TimeTextWithFullDateAndTimeFormat

@Composable
fun TimeTextWithFullDateAndTimeFormat() {
    TimeText(
        timeSource =
            TimeTextDefaults.timeSource(
                DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyy-MM-dd hh:mm")
            )
    )
}

TimeTextWithStatus

@Composable
fun TimeTextWithStatus() {
    val leadingTextStyle = TimeTextDefaults.timeTextStyle(color = MaterialTheme.colors.primary)
    TimeText(
        startLinearContent = { Text(text = "ETA 12:48", style = leadingTextStyle) },
        startCurvedContent = {
            curvedText(text = "ETA 12:48", style = CurvedTextStyle(leadingTextStyle))
        },
    )
}