Skip to content

Commit 9fc0f8d

Browse files
Merge pull request #9969 from rafaeltonholo/feat/9961/in-app-notifications-show-learn-more-on-text-overflow
feat(in-app-notifications): add Learn more CTA when supporting text overflows on banner inline notifications
2 parents 598647e + f9966e1 commit 9fc0f8d

File tree

8 files changed

+80
-20
lines changed

8 files changed

+80
-20
lines changed

core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
44
import androidx.compose.ui.Modifier
55
import androidx.compose.ui.graphics.Color
66
import androidx.compose.ui.text.AnnotatedString
7+
import androidx.compose.ui.text.TextLayoutResult
78
import androidx.compose.ui.text.style.TextAlign
89
import androidx.compose.ui.text.style.TextOverflow
910
import app.k9mail.core.ui.compose.theme2.MainTheme
@@ -17,6 +18,7 @@ fun TextBodyMedium(
1718
textAlign: TextAlign? = null,
1819
overflow: TextOverflow = TextOverflow.Clip,
1920
maxLines: Int = Int.MAX_VALUE,
21+
onTextLayout: (TextLayoutResult) -> Unit = {},
2022
) {
2123
Material3Text(
2224
text = text,
@@ -26,6 +28,7 @@ fun TextBodyMedium(
2628
overflow = overflow,
2729
maxLines = maxLines,
2830
style = MainTheme.typography.bodyMedium,
31+
onTextLayout = onTextLayout,
2932
)
3033
}
3134

@@ -37,6 +40,7 @@ fun TextBodyMedium(
3740
textAlign: TextAlign? = null,
3841
overflow: TextOverflow = TextOverflow.Clip,
3942
maxLines: Int = Int.MAX_VALUE,
43+
onTextLayout: (TextLayoutResult) -> Unit = {},
4044
) {
4145
Material3Text(
4246
text = text,
@@ -46,5 +50,6 @@ fun TextBodyMedium(
4650
overflow = overflow,
4751
maxLines = maxLines,
4852
style = MainTheme.typography.bodyMedium,
53+
onTextLayout = onTextLayout,
4954
)
5055
}

core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import androidx.compose.ui.Alignment
1414
import androidx.compose.ui.Modifier
1515
import androidx.compose.ui.graphics.Shape
1616
import androidx.compose.ui.text.AnnotatedString
17+
import androidx.compose.ui.text.TextLayoutResult
1718
import androidx.compose.ui.text.style.TextOverflow
1819
import app.k9mail.core.ui.compose.designsystem.atom.card.CardColors
1920
import app.k9mail.core.ui.compose.designsystem.atom.card.CardOutlined
@@ -54,6 +55,7 @@ internal fun BannerInlineNotificationCard(
5455
border: BorderStroke = BannerNotificationCardDefaults.errorCardBorder(),
5556
shape: Shape = BannerNotificationCardDefaults.bannerInlineShape,
5657
behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour,
58+
onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {},
5759
) {
5860
val maxLines = when (behaviour) {
5961
BannerInlineNotificationCardBehaviour.Clipped -> 2
@@ -74,6 +76,11 @@ internal fun BannerInlineNotificationCard(
7476
supportingText = supportingText,
7577
behaviour = behaviour,
7678
maxLines = maxLines,
79+
onTextOverflow = { hasVisualOverflow ->
80+
if (behaviour == BannerInlineNotificationCardBehaviour.Clipped) {
81+
onSupportingTextOverflow(hasVisualOverflow)
82+
}
83+
},
7784
)
7885
},
7986
actions = actions,
@@ -186,11 +193,12 @@ private fun BannerInlineNotificationTitle(
186193
}
187194

188195
@Composable
189-
fun BannerInlineNotificationSupportingText(
196+
private fun BannerInlineNotificationSupportingText(
190197
supportingText: CharSequence,
191198
behaviour: BannerInlineNotificationCardBehaviour,
192199
maxLines: Int,
193200
modifier: Modifier = Modifier,
201+
onTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {},
194202
) {
195203
val clippedSupportingText = remember(supportingText, behaviour) {
196204
when (behaviour) {
@@ -200,26 +208,32 @@ fun BannerInlineNotificationSupportingText(
200208
else -> supportingText
201209
}
202210
}
211+
val onTextLayout = remember<(TextLayoutResult) -> Unit>(onTextOverflow) {
212+
{ textLayoutResult -> onTextOverflow(textLayoutResult.hasVisualOverflow) }
213+
}
203214
when (clippedSupportingText) {
204215
is String -> TextBodyMedium(
205216
text = clippedSupportingText,
206217
maxLines = maxLines,
207218
overflow = TextOverflow.Ellipsis,
208219
modifier = modifier,
220+
onTextLayout = onTextLayout,
209221
)
210222

211223
is AnnotatedString -> TextBodyMedium(
212224
text = clippedSupportingText,
213225
maxLines = maxLines,
214226
overflow = TextOverflow.Ellipsis,
215227
modifier = modifier,
228+
onTextLayout = onTextLayout,
216229
)
217230

218231
else -> TextBodyMedium(
219232
text = clippedSupportingText.toString(),
220233
maxLines = maxLines,
221234
overflow = TextOverflow.Ellipsis,
222235
modifier = modifier,
236+
onTextLayout = onTextLayout,
223237
)
224238
}
225239
}

core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ fun ErrorBannerInlineNotificationCard(
2525
actions: @Composable RowScope.() -> Unit,
2626
modifier: Modifier = Modifier,
2727
behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour,
28+
onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {},
2829
) {
2930
BannerInlineNotificationCard(
3031
icon = { Icon(imageVector = Icons.Outlined.Report) },
@@ -35,5 +36,6 @@ fun ErrorBannerInlineNotificationCard(
3536
behaviour = behaviour,
3637
colors = BannerNotificationCardDefaults.errorCardColors(),
3738
border = BannerNotificationCardDefaults.errorCardBorder(),
39+
onSupportingTextOverflow = onSupportingTextOverflow,
3840
)
3941
}

core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ fun InfoBannerInlineNotificationCard(
2525
actions: @Composable RowScope.() -> Unit,
2626
modifier: Modifier = Modifier,
2727
behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour,
28+
onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {},
2829
) {
2930
BannerInlineNotificationCard(
3031
icon = { Icon(imageVector = Icons.Outlined.Info) },
@@ -35,5 +36,6 @@ fun InfoBannerInlineNotificationCard(
3536
behaviour = behaviour,
3637
colors = BannerNotificationCardDefaults.infoCardColors(),
3738
border = BannerNotificationCardDefaults.infoCardBorder(),
39+
onSupportingTextOverflow = onSupportingTextOverflow,
3840
)
3941
}

core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ fun SuccessBannerInlineNotificationCard(
2525
actions: @Composable RowScope.() -> Unit,
2626
modifier: Modifier = Modifier,
2727
behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour,
28+
onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {},
2829
) {
2930
BannerInlineNotificationCard(
3031
icon = { Icon(imageVector = Icons.Outlined.CheckCircle) },
@@ -35,5 +36,6 @@ fun SuccessBannerInlineNotificationCard(
3536
behaviour = behaviour,
3637
colors = BannerNotificationCardDefaults.successCardColors(),
3738
border = BannerNotificationCardDefaults.successCardBorder(),
39+
onSupportingTextOverflow = onSupportingTextOverflow,
3840
)
3941
}

core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ fun WarningBannerInlineNotificationCard(
2626
actions: @Composable RowScope.() -> Unit,
2727
modifier: Modifier = Modifier,
2828
behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour,
29+
onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {},
2930
) {
3031
BannerInlineNotificationCard(
3132
icon = { Icon(imageVector = Icons.Outlined.Warning) },
@@ -36,5 +37,6 @@ fun WarningBannerInlineNotificationCard(
3637
behaviour = behaviour,
3738
colors = BannerNotificationCardDefaults.warningCardColors(),
3839
border = BannerNotificationCardDefaults.warningCardBorder(),
40+
onSupportingTextOverflow = onSupportingTextOverflow,
3941
)
4042
}

feature/notification/api/src/androidMain/kotlin/net/thunderbird/feature/notification/api/ui/BannerInlineNotificationListHost.kt

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import androidx.compose.foundation.layout.padding
99
import androidx.compose.runtime.Composable
1010
import androidx.compose.runtime.collectAsState
1111
import androidx.compose.runtime.getValue
12+
import androidx.compose.runtime.mutableStateOf
1213
import androidx.compose.runtime.remember
14+
import androidx.compose.runtime.setValue
1315
import androidx.compose.ui.Modifier
1416
import app.k9mail.core.ui.compose.designsystem.molecule.notification.NotificationActionButton
1517
import app.k9mail.core.ui.compose.designsystem.organism.banner.inline.BannerInlineNotificationCardBehaviour
@@ -21,13 +23,15 @@ import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListH
2123
import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_CHECK_ERROR_NOTIFICATIONS
2224
import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_CHECK_ERROR_NOTIFICATIONS_ACTION
2325
import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_HOST_PARENT
26+
import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_LEARN_MORE_ACTION
2427
import net.thunderbird.feature.notification.api.ui.action.NotificationAction
2528
import net.thunderbird.feature.notification.api.ui.action.ResolvedNotificationActionButton
2629
import net.thunderbird.feature.notification.api.ui.animation.bannerSlideInSlideOutAnimationSpec
2730
import net.thunderbird.feature.notification.api.ui.host.InAppNotificationHostStateHolder
2831
import net.thunderbird.feature.notification.api.ui.host.visual.BannerInlineVisual
2932
import net.thunderbird.feature.notification.resources.api.Res
3033
import net.thunderbird.feature.notification.resources.api.banner_inline_notification_check_error_notifications
34+
import net.thunderbird.feature.notification.resources.api.banner_inline_notification_learn_more
3135
import net.thunderbird.feature.notification.resources.api.banner_inline_notification_open_notifications
3236
import net.thunderbird.feature.notification.resources.api.banner_inline_notification_some_messages_need_attention
3337
import org.jetbrains.compose.resources.stringResource
@@ -105,25 +109,11 @@ private fun BannerInlineNotificationListHostLayout(
105109
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.half),
106110
) {
107111
displayableNotifications.forEachIndexed { index, banner ->
108-
ErrorBannerInlineNotificationCard(
109-
title = banner.title,
110-
supportingText = banner.supportingText,
111-
actions = {
112-
banner.actions.forEachIndexed { actionIndex, action ->
113-
ResolvedNotificationActionButton(
114-
action = action,
115-
onActionClick = onActionClick,
116-
modifier = Modifier.testTagAsResourceId(
117-
tag = BannerInlineNotificationListHostDefaults.testTagBannerInlineListItemAction(
118-
index = index,
119-
actionIndex = actionIndex,
120-
),
121-
),
122-
)
123-
}
124-
},
125-
behaviour = BannerInlineNotificationCardBehaviour.Clipped,
126-
modifier = Modifier.animateContentSize(),
112+
BannerInlineItem(
113+
index = index,
114+
banner = banner,
115+
onActionClick = onActionClick,
116+
onOpenErrorNotificationsClick = onOpenErrorNotificationsClick,
127117
)
128118
}
129119

@@ -150,11 +140,53 @@ private fun BannerInlineNotificationListHostLayout(
150140
}
151141
}
152142

143+
@Composable
144+
private fun BannerInlineItem(
145+
index: Int,
146+
banner: BannerInlineVisual,
147+
onActionClick: (NotificationAction) -> Unit,
148+
onOpenErrorNotificationsClick: () -> Unit,
149+
modifier: Modifier = Modifier,
150+
) {
151+
var hasSupportingTextOverflowed by remember { mutableStateOf(false) }
152+
ErrorBannerInlineNotificationCard(
153+
title = banner.title,
154+
supportingText = banner.supportingText,
155+
actions = {
156+
if (hasSupportingTextOverflowed) {
157+
NotificationActionButton(
158+
text = stringResource(
159+
resource = Res.string.banner_inline_notification_learn_more,
160+
),
161+
onClick = onOpenErrorNotificationsClick,
162+
modifier = Modifier.testTagAsResourceId(TEST_TAG_LEARN_MORE_ACTION),
163+
)
164+
}
165+
banner.actions.forEachIndexed { actionIndex, action ->
166+
ResolvedNotificationActionButton(
167+
action = action,
168+
onActionClick = onActionClick,
169+
modifier = Modifier.testTagAsResourceId(
170+
tag = BannerInlineNotificationListHostDefaults.testTagBannerInlineListItemAction(
171+
index = index,
172+
actionIndex = actionIndex,
173+
),
174+
),
175+
)
176+
}
177+
},
178+
behaviour = BannerInlineNotificationCardBehaviour.Clipped,
179+
modifier = modifier.animateContentSize(),
180+
onSupportingTextOverflow = { hasSupportingTextOverflowed = it },
181+
)
182+
}
183+
153184
object BannerInlineNotificationListHostDefaults {
154185
internal const val TEST_TAG_HOST_PARENT = "banner_inline_notification_host"
155186
internal const val TEST_TAG_BANNER_INLINE_LIST = "banner_inline_notification_list"
156187
internal const val TEST_TAG_CHECK_ERROR_NOTIFICATIONS = "check_notifications_composable"
157188
internal const val TEST_TAG_CHECK_ERROR_NOTIFICATIONS_ACTION = "check_notifications_action"
189+
internal const val TEST_TAG_LEARN_MORE_ACTION = "learn_more_action"
158190

159191
internal fun testTagBannerInlineListItemAction(index: Int, actionIndex: Int) =
160192
"banner_inline_notification_list_item_action_${index}_$actionIndex"

feature/notification/api/src/commonMain/composeResources/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,6 @@
6060
<string name="banner_inline_notification_check_error_notifications">Check Error Notifications</string>
6161
<string name="banner_inline_notification_some_messages_need_attention">Some messages need your attention.</string>
6262
<string name="banner_inline_notification_open_notifications">Open notifications</string>
63+
<string name="banner_inline_notification_learn_more">Learn more</string>
6364
<string name="banner_inline_notification_view_support_article">View support article</string>
6465
</resources>

0 commit comments

Comments
 (0)