Skip to content

Commit 559e634

Browse files
committed
Add rich text for alert message
1 parent 044c28c commit 559e634

2 files changed

Lines changed: 151 additions & 18 deletions

File tree

core/src/main/java/com/orange/ouds/core/component/OudsAlertMessage.kt

Lines changed: 105 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ import androidx.compose.ui.platform.LocalConfiguration
4545
import androidx.compose.ui.res.painterResource
4646
import androidx.compose.ui.res.stringResource
4747
import androidx.compose.ui.semantics.semantics
48+
import androidx.compose.ui.text.AnnotatedString
4849
import androidx.compose.ui.tooling.preview.Preview
4950
import androidx.compose.ui.tooling.preview.PreviewParameter
5051
import androidx.compose.ui.unit.dp
5152
import com.orange.ouds.core.R
53+
import com.orange.ouds.core.component.common.text.OudsAnnotatedAlertMessageString
5254
import com.orange.ouds.core.component.content.OudsComponentContent
5355
import com.orange.ouds.core.theme.LocalDrawableResources
5456
import com.orange.ouds.core.theme.LocalThemeSettings
@@ -59,6 +61,7 @@ import com.orange.ouds.core.utilities.OudsPreview
5961
import com.orange.ouds.core.utilities.OudsPreviewDevice
6062
import com.orange.ouds.core.utilities.OudsPreviewableComponent
6163
import com.orange.ouds.core.utilities.getPreviewTheme
64+
import com.orange.ouds.foundation.extensions.orElse
6265
import com.orange.ouds.foundation.utilities.BasicPreviewParameterProvider
6366
import com.orange.ouds.theme.OudsThemeContract
6467

@@ -107,6 +110,90 @@ fun OudsAlertMessage(
107110
onClose: (() -> Unit)? = null,
108111
actionLink: OudsAlertMessageActionLink? = null,
109112
bulletList: List<String>? = null
113+
) {
114+
OudsAlertMessage(
115+
label = label,
116+
modifier = modifier,
117+
status = status,
118+
description = description,
119+
annotatedDescription = null,
120+
onClose = onClose,
121+
actionLink = actionLink,
122+
bulletList = bulletList,
123+
annotatedBulletList = null
124+
)
125+
}
126+
127+
/**
128+
* Alert message is a UI element that displays system feedback, status changes or required action; throughout detailed, prominent, persistent and actionable
129+
* communication. Alert message includes functional icon and semantic colour, and may include as well a close button and/or action link.
130+
* Alert Message does not disappear automatically and remains visible until dismissed or resolved by the user.
131+
*
132+
* > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-alert-message)
133+
*
134+
* > Design version: 1.1.0
135+
*
136+
* @param label Label displayed in the alert message. Main message that should be short, clear, and readable at a glance.
137+
* @param modifier [Modifier] applied to the alert message.
138+
* @param status The status of the alert message. Its background color and its icon color are based on this status.
139+
* There are two types of statuses:
140+
* - Non-functional statuses ([OudsAlertMessageStatus.Neutral] or [OudsAlertMessageStatus.Accent]) used for informational or decorative alert messages. They
141+
* provide context or highlight content without implying a specific state, system event, or user action. These alerts are not tied to UX patterns such as
142+
* success, error, or warning, and may use contextual or brand-related icons to enhance recognition or storytelling.
143+
* - Functional statuses communicate specific system statuses, results, or user feedback: [OudsAlertMessageStatus.Positive], [OudsAlertMessageStatus.Warning],
144+
* [OudsAlertMessageStatus.Negative], [OudsAlertMessageStatus.Info].
145+
* Each variant conveys a clear semantic meaning and must always be paired with its dedicated functional icon to ensure clarity and accessibility.
146+
* Use functional alerts to inform user about state changes, confirmations, or issues that are directly connected to system logic or user actions. These
147+
* messages carry functional meaning and help guide user response or acknowledgment.
148+
* @param description Annotated supplementary text in an alert message. Use only when additional detail or guidance is needed beyond the label. It should remain
149+
* short, clear and scannable, helping the user to understand what happened and what he can do next.
150+
* @param onClose Callback invoked when the close button is clicked. If `null`, the close button is not displayed and the alert message remains visible until
151+
* the context changes (e.g., the issue is resolved, the screen is refreshed). Otherwise, the alert message is dismissable and includes a close button,
152+
* allowing the user to dismiss it when he has acknowledged the message.
153+
* Some alerts must remain visible to ensure user is aware of important information; others can be closed to reduce visual clutter.
154+
* @param actionLink An optional link to be displayed in the alert message. It can be used to trigger an action.
155+
* @param bulletList A list of annotated bullet points to be displayed in the alert message following the label or the optional [description].
156+
* Add this list when you need to highlight multiple points, such as service features, plan details, or next steps. Each bullet should be short and written
157+
* as a clear phrase or fragment — avoid long sentences or complex structures.
158+
*
159+
* @sample com.orange.ouds.core.component.samples.OudsAlertMessageSample
160+
*
161+
* @sample com.orange.ouds.core.component.samples.OudsAlertMessageFunctionalWithTopEndActionLinkSample
162+
*/
163+
@Composable
164+
fun OudsAlertMessage(
165+
label: String,
166+
modifier: Modifier = Modifier,
167+
status: OudsAlertMessageStatus = OudsAlertMessageDefaults.Status,
168+
description: OudsAnnotatedAlertMessageString,
169+
onClose: (() -> Unit)? = null,
170+
actionLink: OudsAlertMessageActionLink? = null,
171+
bulletList: List<OudsAnnotatedAlertMessageString>?
172+
) {
173+
OudsAlertMessage(
174+
label = label,
175+
modifier = modifier,
176+
status = status,
177+
description = null,
178+
annotatedDescription = description,
179+
onClose = onClose,
180+
actionLink = actionLink,
181+
bulletList = null,
182+
annotatedBulletList = bulletList
183+
)
184+
}
185+
186+
@Composable
187+
private fun OudsAlertMessage(
188+
label: String,
189+
modifier: Modifier = Modifier,
190+
status: OudsAlertMessageStatus = OudsAlertMessageDefaults.Status,
191+
description: String? = null,
192+
annotatedDescription: OudsAnnotatedAlertMessageString? = null,
193+
onClose: (() -> Unit)? = null,
194+
actionLink: OudsAlertMessageActionLink? = null,
195+
bulletList: List<String>? = null,
196+
annotatedBulletList: List<OudsAnnotatedAlertMessageString>? = null
110197
) {
111198
with(OudsTheme.componentsTokens.alert) {
112199
val scale = LocalConfiguration.current.fontScale
@@ -150,15 +237,15 @@ fun OudsAlertMessage(
150237
color = status.contentColor,
151238
style = OudsTheme.typography.label.moderate.large
152239
)
153-
description?.let {
154-
Text(
155-
modifier = Modifier.widthIn(max = OudsTheme.sizes.maxWidth.type.label.medium),
156-
text = description,
157-
color = status.contentColor,
158-
style = OudsTheme.typography.label.default.medium
159-
)
240+
val descriptionModifier = Modifier.widthIn(max = OudsTheme.sizes.maxWidth.type.label.medium)
241+
val descriptionText = annotatedDescription?.annotatedString.orElse { description }
242+
val descriptionColor = status.contentColor
243+
val descriptionStyle = OudsTheme.typography.label.default.medium
244+
when (descriptionText) {
245+
is AnnotatedString -> Text(modifier = descriptionModifier, text = descriptionText, color = descriptionColor, style = descriptionStyle)
246+
is String -> Text(modifier = descriptionModifier, text = descriptionText, color = descriptionColor, style = descriptionStyle)
160247
}
161-
bulletList?.let { list ->
248+
annotatedBulletList.orElse { bulletList }?.let { list ->
162249
Column(verticalArrangement = Arrangement.spacedBy(spaceRowGapBullet.value)) {
163250
list.forEach { label ->
164251
if (label.isNotBlank()) OudsAlertMessageBulletListItem(label = label, color = status.contentColor)
@@ -360,7 +447,7 @@ sealed class OudsAlertMessageStatus(internal val value: OudsAlertStatus, val ico
360447
}
361448

362449
@Composable
363-
private fun OudsAlertMessageBulletListItem(label: String, color: Color) {
450+
private fun OudsAlertMessageBulletListItem(label: CharSequence, color: Color) {
364451
val scale = LocalConfiguration.current.fontScale
365452
Row(
366453
modifier = Modifier
@@ -383,15 +470,15 @@ private fun OudsAlertMessageBulletListItem(label: String, color: Color) {
383470
tint = color
384471
)
385472
}
386-
Text(
387-
modifier = Modifier
388-
.fillMaxHeight()
389-
.wrapContentHeight() // Allows to center the text vertically when its height is smaller than the row height
390-
.widthIn(max = OudsTheme.sizes.maxWidth.type.label.medium),
391-
text = label,
392-
style = OudsTheme.typography.label.default.medium,
393-
color = color
394-
)
473+
val modifier = Modifier
474+
.fillMaxHeight()
475+
.wrapContentHeight() // Allows to center the text vertically when its height is smaller than the row height
476+
.widthIn(max = OudsTheme.sizes.maxWidth.type.label.medium)
477+
val style = OudsTheme.typography.label.default.medium
478+
when (label) {
479+
is AnnotatedString -> Text(modifier = modifier, text = label, color = color, style = style)
480+
is String -> Text(modifier = modifier, text = label, color = color, style = style)
481+
}
395482
}
396483
}
397484

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Software Name: OUDS Android
3+
* SPDX-FileCopyrightText: Copyright (c) Orange SA
4+
* SPDX-License-Identifier: MIT
5+
*
6+
* This software is distributed under the MIT license,
7+
* the text of which is available at https://opensource.org/license/MIT/
8+
* or see the "LICENSE" file for more details.
9+
*
10+
* Software description: Android library of reusable graphical components
11+
*/
12+
13+
package com.orange.ouds.core.component.common.text
14+
15+
import androidx.compose.ui.text.AnnotatedString
16+
17+
class OudsAnnotatedAlertMessageString internal constructor(annotatedString: AnnotatedString) :
18+
OudsAnnotatedString<OudsAnnotatedAlertMessageString>(annotatedString) {
19+
20+
class Builder(capacity: Int = 16) :
21+
OudsAnnotatedString.Builder<OudsAnnotatedAlertMessageString>(capacity, OudsAnnotatedAlertMessageString::class.java),
22+
StrongBuilder, LinkBuilder {
23+
24+
constructor(text: String) : this() {
25+
append(text)
26+
}
27+
28+
constructor(text: OudsAnnotatedHelperText) : this() {
29+
append(text)
30+
}
31+
32+
override fun addStrong(start: Int, end: Int) = addStrongInternal(start, end)
33+
34+
override fun pushStrong(): Int = pushStrongInternal()
35+
36+
override fun addLink(url: OudsLinkAnnotation.Url, start: Int, end: Int) = addLinkInternal(url, start, end)
37+
38+
override fun addLink(clickable: OudsLinkAnnotation.Clickable, start: Int, end: Int) = addLinkInternal(clickable, start, end)
39+
40+
override fun pushLink(link: OudsLinkAnnotation): Int = pushLinkInternal(link)
41+
}
42+
}
43+
44+
fun buildOudsAnnotatedAlertMessageString(builder: (OudsAnnotatedAlertMessageString.Builder).() -> Unit): OudsAnnotatedAlertMessageString {
45+
return buildOudsAnnotatedString<OudsAnnotatedAlertMessageString.Builder, OudsAnnotatedAlertMessageString>(builder)
46+
}

0 commit comments

Comments
 (0)