diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt index e7bbc1b37da..65a89395c4a 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import app.k9mail.core.ui.compose.theme2.MainTheme @@ -17,6 +18,7 @@ fun TextBodyMedium( textAlign: TextAlign? = null, overflow: TextOverflow = TextOverflow.Clip, maxLines: Int = Int.MAX_VALUE, + onTextLayout: (TextLayoutResult) -> Unit = {}, ) { Material3Text( text = text, @@ -26,6 +28,7 @@ fun TextBodyMedium( overflow = overflow, maxLines = maxLines, style = MainTheme.typography.bodyMedium, + onTextLayout = onTextLayout, ) } @@ -37,6 +40,7 @@ fun TextBodyMedium( textAlign: TextAlign? = null, overflow: TextOverflow = TextOverflow.Clip, maxLines: Int = Int.MAX_VALUE, + onTextLayout: (TextLayoutResult) -> Unit = {}, ) { Material3Text( text = text, @@ -46,5 +50,6 @@ fun TextBodyMedium( overflow = overflow, maxLines = maxLines, style = MainTheme.typography.bodyMedium, + onTextLayout = onTextLayout, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt index 7995435ce55..921bb431022 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.style.TextOverflow import app.k9mail.core.ui.compose.designsystem.atom.card.CardColors import app.k9mail.core.ui.compose.designsystem.atom.card.CardOutlined @@ -54,6 +55,7 @@ internal fun BannerInlineNotificationCard( border: BorderStroke = BannerNotificationCardDefaults.errorCardBorder(), shape: Shape = BannerNotificationCardDefaults.bannerInlineShape, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { val maxLines = when (behaviour) { BannerInlineNotificationCardBehaviour.Clipped -> 2 @@ -74,6 +76,11 @@ internal fun BannerInlineNotificationCard( supportingText = supportingText, behaviour = behaviour, maxLines = maxLines, + onTextOverflow = { hasVisualOverflow -> + if (behaviour == BannerInlineNotificationCardBehaviour.Clipped) { + onSupportingTextOverflow(hasVisualOverflow) + } + }, ) }, actions = actions, @@ -186,11 +193,12 @@ private fun BannerInlineNotificationTitle( } @Composable -fun BannerInlineNotificationSupportingText( +private fun BannerInlineNotificationSupportingText( supportingText: CharSequence, behaviour: BannerInlineNotificationCardBehaviour, maxLines: Int, modifier: Modifier = Modifier, + onTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { val clippedSupportingText = remember(supportingText, behaviour) { when (behaviour) { @@ -200,12 +208,16 @@ fun BannerInlineNotificationSupportingText( else -> supportingText } } + val onTextLayout = remember<(TextLayoutResult) -> Unit>(onTextOverflow) { + { textLayoutResult -> onTextOverflow(textLayoutResult.hasVisualOverflow) } + } when (clippedSupportingText) { is String -> TextBodyMedium( text = clippedSupportingText, maxLines = maxLines, overflow = TextOverflow.Ellipsis, modifier = modifier, + onTextLayout = onTextLayout, ) is AnnotatedString -> TextBodyMedium( @@ -213,6 +225,7 @@ fun BannerInlineNotificationSupportingText( maxLines = maxLines, overflow = TextOverflow.Ellipsis, modifier = modifier, + onTextLayout = onTextLayout, ) else -> TextBodyMedium( @@ -220,6 +233,7 @@ fun BannerInlineNotificationSupportingText( maxLines = maxLines, overflow = TextOverflow.Ellipsis, modifier = modifier, + onTextLayout = onTextLayout, ) } } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt index 25bb7da9a3f..ec31b098099 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt @@ -25,6 +25,7 @@ fun ErrorBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.Report) }, @@ -35,5 +36,6 @@ fun ErrorBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.errorCardColors(), border = BannerNotificationCardDefaults.errorCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt index e835d7d18c8..4a536bfd563 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt @@ -25,6 +25,7 @@ fun InfoBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.Info) }, @@ -35,5 +36,6 @@ fun InfoBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.infoCardColors(), border = BannerNotificationCardDefaults.infoCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt index 102c7c253d7..597bb929551 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt @@ -25,6 +25,7 @@ fun SuccessBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.CheckCircle) }, @@ -35,5 +36,6 @@ fun SuccessBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.successCardColors(), border = BannerNotificationCardDefaults.successCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt index 24cded285b5..253456f35ad 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt @@ -26,6 +26,7 @@ fun WarningBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.Warning) }, @@ -36,5 +37,6 @@ fun WarningBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.warningCardColors(), border = BannerNotificationCardDefaults.warningCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/feature/notification/api/src/androidMain/kotlin/net/thunderbird/feature/notification/api/ui/BannerInlineNotificationListHost.kt b/feature/notification/api/src/androidMain/kotlin/net/thunderbird/feature/notification/api/ui/BannerInlineNotificationListHost.kt index 24c23c79cf6..57fabfeba66 100644 --- a/feature/notification/api/src/androidMain/kotlin/net/thunderbird/feature/notification/api/ui/BannerInlineNotificationListHost.kt +++ b/feature/notification/api/src/androidMain/kotlin/net/thunderbird/feature/notification/api/ui/BannerInlineNotificationListHost.kt @@ -9,7 +9,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import app.k9mail.core.ui.compose.designsystem.molecule.notification.NotificationActionButton import app.k9mail.core.ui.compose.designsystem.organism.banner.inline.BannerInlineNotificationCardBehaviour @@ -21,6 +23,7 @@ import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListH import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_CHECK_ERROR_NOTIFICATIONS import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_CHECK_ERROR_NOTIFICATIONS_ACTION import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_HOST_PARENT +import net.thunderbird.feature.notification.api.ui.BannerInlineNotificationListHostDefaults.TEST_TAG_LEARN_MORE_ACTION import net.thunderbird.feature.notification.api.ui.action.NotificationAction import net.thunderbird.feature.notification.api.ui.action.ResolvedNotificationActionButton import net.thunderbird.feature.notification.api.ui.animation.bannerSlideInSlideOutAnimationSpec @@ -28,6 +31,7 @@ import net.thunderbird.feature.notification.api.ui.host.InAppNotificationHostSta import net.thunderbird.feature.notification.api.ui.host.visual.BannerInlineVisual import net.thunderbird.feature.notification.resources.api.Res import net.thunderbird.feature.notification.resources.api.banner_inline_notification_check_error_notifications +import net.thunderbird.feature.notification.resources.api.banner_inline_notification_learn_more import net.thunderbird.feature.notification.resources.api.banner_inline_notification_open_notifications import net.thunderbird.feature.notification.resources.api.banner_inline_notification_some_messages_need_attention import org.jetbrains.compose.resources.stringResource @@ -105,25 +109,11 @@ private fun BannerInlineNotificationListHostLayout( verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.half), ) { displayableNotifications.forEachIndexed { index, banner -> - ErrorBannerInlineNotificationCard( - title = banner.title, - supportingText = banner.supportingText, - actions = { - banner.actions.forEachIndexed { actionIndex, action -> - ResolvedNotificationActionButton( - action = action, - onActionClick = onActionClick, - modifier = Modifier.testTagAsResourceId( - tag = BannerInlineNotificationListHostDefaults.testTagBannerInlineListItemAction( - index = index, - actionIndex = actionIndex, - ), - ), - ) - } - }, - behaviour = BannerInlineNotificationCardBehaviour.Clipped, - modifier = Modifier.animateContentSize(), + BannerInlineItem( + index = index, + banner = banner, + onActionClick = onActionClick, + onOpenErrorNotificationsClick = onOpenErrorNotificationsClick, ) } @@ -150,11 +140,53 @@ private fun BannerInlineNotificationListHostLayout( } } +@Composable +private fun BannerInlineItem( + index: Int, + banner: BannerInlineVisual, + onActionClick: (NotificationAction) -> Unit, + onOpenErrorNotificationsClick: () -> Unit, + modifier: Modifier = Modifier, +) { + var hasSupportingTextOverflowed by remember { mutableStateOf(false) } + ErrorBannerInlineNotificationCard( + title = banner.title, + supportingText = banner.supportingText, + actions = { + if (hasSupportingTextOverflowed) { + NotificationActionButton( + text = stringResource( + resource = Res.string.banner_inline_notification_learn_more, + ), + onClick = onOpenErrorNotificationsClick, + modifier = Modifier.testTagAsResourceId(TEST_TAG_LEARN_MORE_ACTION), + ) + } + banner.actions.forEachIndexed { actionIndex, action -> + ResolvedNotificationActionButton( + action = action, + onActionClick = onActionClick, + modifier = Modifier.testTagAsResourceId( + tag = BannerInlineNotificationListHostDefaults.testTagBannerInlineListItemAction( + index = index, + actionIndex = actionIndex, + ), + ), + ) + } + }, + behaviour = BannerInlineNotificationCardBehaviour.Clipped, + modifier = modifier.animateContentSize(), + onSupportingTextOverflow = { hasSupportingTextOverflowed = it }, + ) +} + object BannerInlineNotificationListHostDefaults { internal const val TEST_TAG_HOST_PARENT = "banner_inline_notification_host" internal const val TEST_TAG_BANNER_INLINE_LIST = "banner_inline_notification_list" internal const val TEST_TAG_CHECK_ERROR_NOTIFICATIONS = "check_notifications_composable" internal const val TEST_TAG_CHECK_ERROR_NOTIFICATIONS_ACTION = "check_notifications_action" + internal const val TEST_TAG_LEARN_MORE_ACTION = "learn_more_action" internal fun testTagBannerInlineListItemAction(index: Int, actionIndex: Int) = "banner_inline_notification_list_item_action_${index}_$actionIndex" diff --git a/feature/notification/api/src/commonMain/composeResources/values/strings.xml b/feature/notification/api/src/commonMain/composeResources/values/strings.xml index d07dac24ffb..b7f17ab9b2f 100644 --- a/feature/notification/api/src/commonMain/composeResources/values/strings.xml +++ b/feature/notification/api/src/commonMain/composeResources/values/strings.xml @@ -60,5 +60,6 @@ Check Error Notifications Some messages need your attention. Open notifications + Learn more View support article