diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt index 5b8fab6edea..6856aa145f0 100644 --- a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/AppNotification.kt @@ -11,6 +11,8 @@ import net.thunderbird.feature.notification.api.NotificationGroup import net.thunderbird.feature.notification.api.NotificationSeverity import net.thunderbird.feature.notification.api.ui.action.NotificationAction import net.thunderbird.feature.notification.api.ui.icon.NotificationIcon +import net.thunderbird.feature.notification.api.ui.style.InAppNotificationStyle +import net.thunderbird.feature.notification.api.ui.style.SystemNotificationStyle /** * Represents a notification that can be displayed to the user. @@ -62,12 +64,17 @@ sealed class AppNotification : Notification { * @property subText Additional text displayed below the content text, can be null. * @property channel The notification channel to which this notification belongs. * @property group The notification group to which this notification belongs, can be null. + * @property systemNotificationStyle The style of the system notification. + * Defaults to [SystemNotificationStyle.Undefined]. * @see LockscreenNotificationAppearance + * @see SystemNotificationStyle + * @see net.thunderbird.feature.notification.api.ui.style.systemNotificationStyle */ sealed interface SystemNotification : Notification { val subText: String? get() = null val channel: NotificationChannel val group: NotificationGroup? get() = null + val systemNotificationStyle: SystemNotificationStyle get() = SystemNotificationStyle.Undefined /** * Converts this notification to a [LockscreenNotification]. @@ -95,10 +102,16 @@ sealed interface SystemNotification : Notification { } /** - * * Represents a notification displayed within the application. * * In-app notifications are typically less intrusive than system notifications and **do not require** * system notification permissions to be displayed. + * + * @property inAppNotificationStyle The style of the in-app notification. + * Defaults to [InAppNotificationStyle.Undefined]. + * @see InAppNotificationStyle + * @see net.thunderbird.feature.notification.api.ui.style.inAppNotificationStyle */ -sealed interface InAppNotification : Notification +sealed interface InAppNotification : Notification { + val inAppNotificationStyle: InAppNotificationStyle get() = InAppNotificationStyle.Undefined +} diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/MailNotification.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/MailNotification.kt index 593ff690674..0f2220b2ba9 100644 --- a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/MailNotification.kt +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/content/MailNotification.kt @@ -12,6 +12,8 @@ import net.thunderbird.feature.notification.api.ui.icon.NewMailSingleMail import net.thunderbird.feature.notification.api.ui.icon.NewMailSummaryMail import net.thunderbird.feature.notification.api.ui.icon.NotificationIcon import net.thunderbird.feature.notification.api.ui.icon.NotificationIcons +import net.thunderbird.feature.notification.api.ui.style.SystemNotificationStyle +import net.thunderbird.feature.notification.api.ui.style.systemNotificationStyle import net.thunderbird.feature.notification.resources.api.Res import net.thunderbird.feature.notification.resources.api.notification_additional_messages import net.thunderbird.feature.notification.resources.api.notification_bg_send_ticker @@ -126,6 +128,7 @@ sealed class MailNotification : AppNotification(), SystemNotification { SystemNotification.LockscreenNotification( notification = copy(contentText = null), ) + override val actions: Set = setOf(NotificationAction.Retry) companion object { @@ -188,6 +191,9 @@ sealed class MailNotification : AppNotification(), SystemNotification { NotificationAction.Archive, NotificationAction.MarkAsSpam, ) + override val systemNotificationStyle: SystemNotificationStyle = systemNotificationStyle { + bigText(preview) + } } /** diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/InAppNotificationStyle.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/InAppNotificationStyle.kt new file mode 100644 index 00000000000..263ab7d89ec --- /dev/null +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/InAppNotificationStyle.kt @@ -0,0 +1,78 @@ +package net.thunderbird.feature.notification.api.ui.style + +import net.thunderbird.feature.notification.api.ui.style.builder.InAppNotificationStyleBuilder + +/** + * Represents the style of an in-app notification. + * + * In-app notifications are displayed within the application itself to provide immediate + * feedback or information. + * + * TODO(#9312): The subtypes of [InAppNotificationStyle] Style might change after designer's feedback. + */ +enum class InAppNotificationStyle { + /** + * Represents an undefined in-app notification style. + * This can be used as a default or placeholder when no specific style is applicable. + */ + Undefined, + + /** + * Represents a fatal error notification that cannot be dismissed by the user. + * + * This type of notification typically indicates a fatal issue that requires user attention + * and prevents normal operation of the application. + */ + Fatal, + + /** + * Represents a critical in-app notification style. + * + * This style is used for important messages that require user attention but do not + * necessarily halt the application's functionality like a [Fatal] error. + */ + Critical, + + /** + * Represents a temporary in-app notification style. + * + * This style is typically used for notifications that are displayed briefly and then dismissed + * automatically or by user interaction. + */ + Temporary, + + /** + * Represents a general warning notification. + */ + Warning, + + /** + * Represents an in-app notification that displays general information. + * + * This style is typically used for notifications that convey important updates or messages + * that don't fit into more specific categories like errors or successes. + */ + Information, +} + +/** + * Configures the in-app notification style. + * + * @param builder A lambda function with [InAppNotificationStyleBuilder] as its receiver, + * used to configure the system notification style. + * + * Example: + * ``` + * inAppNotificationStyle { + * severity(NotificationSeverity.Fatal) + * } + * ``` + * + * TODO(#9312): The subtypes of [InAppNotificationStyle] Style might change after designer's feedback. + */ +@NotificationStyleMarker +fun inAppNotificationStyle( + builder: @NotificationStyleMarker InAppNotificationStyleBuilder.() -> Unit, +): InAppNotificationStyle { + return InAppNotificationStyleBuilder().apply(builder).build() +} diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/NotificationStyleMarker.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/NotificationStyleMarker.kt new file mode 100644 index 00000000000..55c6a387e60 --- /dev/null +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/NotificationStyleMarker.kt @@ -0,0 +1,29 @@ +package net.thunderbird.feature.notification.api.ui.style + +/** + * A DSL marker for building notification styles. + * + * This annotation is used to restrict the scope of lambda receivers, ensuring that + * methods belonging to an outer scope cannot be called from an inner scope. + * This helps in creating a more structured and type-safe DSL for constructing + * different notification styles. + * + * Example: + * ``` + * // OK: + * val systemStyle = systemNotificationStyle { + * bigText("This is a big text notification.") + * } + * + * // Compile error: + * val systemStyle = systemNotificationStyle { + * inbox { + * // bigText must be called within systemNotificationStyle and not within inbox configuration. + * bigText("This is a big text notification.") + * } + * } + * ``` + */ +@DslMarker +@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) +internal annotation class NotificationStyleMarker diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/SystemNotificationStyle.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/SystemNotificationStyle.kt new file mode 100644 index 00000000000..80cd161274e --- /dev/null +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/SystemNotificationStyle.kt @@ -0,0 +1,61 @@ +package net.thunderbird.feature.notification.api.ui.style + +import net.thunderbird.feature.notification.api.ui.style.builder.SystemNotificationStyleBuilder +import org.jetbrains.annotations.VisibleForTesting + +/** + * Represents the style of a system notification. + */ +sealed interface SystemNotificationStyle { + /** + * Represents an undefined notification style. + * This can be used as a default or placeholder when no specific style is applicable. + */ + data object Undefined : SystemNotificationStyle + + /** + * Style for large-format notifications that include a lot of text. + * + * @property text The main text content of the notification. + */ + data class BigTextStyle @VisibleForTesting constructor( + val text: String, + ) : SystemNotificationStyle + + /** + * Style for large-format notifications that include a list of (up to 5) strings. + * + * @property bigContentTitle Overrides the title of the notification. + * @property summary Overrides the summary of the notification. + * @property lines List of strings to display in the notification. + */ + data class InboxStyle @VisibleForTesting constructor( + val bigContentTitle: String, + val summary: String, + val lines: List, + ) : SystemNotificationStyle +} + +/** + * Configures the system notification style. + * + * @param builder A lambda function with [SystemNotificationStyleBuilder] as its receiver, + * used to configure the system notification style. + * + * Example: + * ``` + * systemNotificationStyle { + * bigText("This is a big text notification.") + * // or + * inbox { + * // Add more inbox style configurations here + * } + * } + * ``` + */ +@NotificationStyleMarker +fun systemNotificationStyle( + builder: @NotificationStyleMarker SystemNotificationStyleBuilder.() -> Unit, +): SystemNotificationStyle { + return SystemNotificationStyleBuilder().apply(builder).build() +} diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/InAppNotificationStyleBuilder.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/InAppNotificationStyleBuilder.kt new file mode 100644 index 00000000000..0895523a66b --- /dev/null +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/InAppNotificationStyleBuilder.kt @@ -0,0 +1,42 @@ +package net.thunderbird.feature.notification.api.ui.style.builder + +import net.thunderbird.feature.notification.api.NotificationSeverity +import net.thunderbird.feature.notification.api.ui.style.InAppNotificationStyle + +/** + * Builder for creating [InAppNotificationStyle] instances. + * This interface defines the methods available for configuring the style of an in-app notification. + */ +class InAppNotificationStyleBuilder internal constructor() { + private var style = InAppNotificationStyle.Undefined + + /** + * Sets the severity of the in-app notification. + * + * @param severity The severity level for the notification. + */ + fun severity(severity: NotificationSeverity) { + require(style == InAppNotificationStyle.Undefined) { + "In-App Notifications must have only one severity." + } + style = when (severity) { + NotificationSeverity.Fatal -> InAppNotificationStyle.Fatal + NotificationSeverity.Critical -> InAppNotificationStyle.Critical + NotificationSeverity.Temporary -> InAppNotificationStyle.Temporary + NotificationSeverity.Warning -> InAppNotificationStyle.Warning + NotificationSeverity.Information -> InAppNotificationStyle.Information + } + } + + /** + * Builds the [InAppNotificationStyle] based on the provided parameters. + * + * @return The constructed [InAppNotificationStyle]. + */ + internal fun build(): InAppNotificationStyle { + check(style != InAppNotificationStyle.Undefined) { + "You must add severity of the in-app notification." + } + return style + } +} diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/InboxSystemNotificationStyleBuilder.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/InboxSystemNotificationStyleBuilder.kt new file mode 100644 index 00000000000..363eedece4a --- /dev/null +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/InboxSystemNotificationStyleBuilder.kt @@ -0,0 +1,82 @@ +package net.thunderbird.feature.notification.api.ui.style.builder + +import net.thunderbird.feature.notification.api.ui.style.SystemNotificationStyle +import org.jetbrains.annotations.VisibleForTesting + +@VisibleForTesting +internal const val MAX_LINES = 5 +private const val MAX_LINES_ERROR_MESSAGE = "The maximum number of lines for a inbox notification is $MAX_LINES" + +/** + * Builder for [SystemNotificationStyle.InboxStyle]. + * + * This style is used to display a list of items in the notification's content. + * It is commonly used for email or messaging apps. + */ +class InboxSystemNotificationStyleBuilder internal constructor( + private var bigContentTitle: String? = null, + private var summary: String? = null, + private val lines: MutableList = mutableListOf(), +) { + /** + * Sets the title for the notification's big content view. + * + * This method is used to specify the main title text that will be displayed + * when the notification is expanded to show its detailed content. + * + * @param title The string to be used as the big content title. + */ + fun title(title: String) { + bigContentTitle = title + } + + /** + * Sets the summary of the item. + * + * @param summary The summary of the item. + */ + fun summary(summary: String) { + this.summary = summary + } + + /** + * Append a line to the digest section of the Inbox notification. + * + * @param line The line to add. + */ + fun line(line: CharSequence) { + require(lines.size < MAX_LINES) { MAX_LINES_ERROR_MESSAGE } + lines += line + } + + /** + * Adds one or more lines to the digest section of the Inbox notification. + * + * @param lines A variable number of CharSequence objects representing the lines to be added. + */ + fun lines(vararg lines: CharSequence) { + require(lines.size < MAX_LINES) { MAX_LINES_ERROR_MESSAGE } + this.lines += lines + } + + /** + * Builds and returns a [SystemNotificationStyle.InboxStyle] object. + * + * This method performs checks to ensure that mandatory fields like the big content title + * and summary are provided before creating the notification style object. + * + * @return A [SystemNotificationStyle.InboxStyle] object configured with the specified + * title, summary, and lines. + * @throws IllegalStateException if the big content title or summary is not set. + */ + @Suppress("VisibleForTests") + internal fun build(): SystemNotificationStyle.InboxStyle = SystemNotificationStyle.InboxStyle( + bigContentTitle = checkNotNull(bigContentTitle) { + "The inbox notification's title is required" + }, + summary = checkNotNull(summary) { + "The inbox notification's summary is required" + }, + lines = lines.toList(), + ) +} diff --git a/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/SystemNotificationStyleBuilder.kt b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/SystemNotificationStyleBuilder.kt new file mode 100644 index 00000000000..54f15540734 --- /dev/null +++ b/feature/notification/api/src/commonMain/kotlin/net/thunderbird/feature/notification/api/ui/style/builder/SystemNotificationStyleBuilder.kt @@ -0,0 +1,95 @@ +package net.thunderbird.feature.notification.api.ui.style.builder + +import kotlin.apply +import net.thunderbird.feature.notification.api.ui.style.NotificationStyleMarker +import net.thunderbird.feature.notification.api.ui.style.SystemNotificationStyle +import net.thunderbird.feature.notification.api.ui.style.SystemNotificationStyle.BigTextStyle +import net.thunderbird.feature.notification.api.ui.style.SystemNotificationStyle.InboxStyle + +/** + * A builder for creating system notification styles. + * + * This builder allows for the creation of either a [BigTextStyle] or an [InboxStyle] for a system notification. + * It ensures that only one style type is set at a time, throwing an error if both are attempted. + * + * Example usage for [BigTextStyle]: + * ``` + * val style = systemNotificationStyle { + * bigText("This is a long piece of text that will be displayed in the expanded notification.") + * } + * ``` + * + * Example usage for [InboxStyle]: + * ``` + * val style = systemNotificationStyle { + * inbox { + * title("5 New Messages") + * summary("You have new messages") + * addLine("Alice: Hey, are you free later?") + * addLine("Bob: Meeting reminder for 3 PM") + * } + * } + * ``` + * @see net.thunderbird.feature.notification.api.ui.style.systemNotificationStyle + */ +class SystemNotificationStyleBuilder internal constructor() { + private var bigText: BigTextStyle? = null + private var inboxStyle: InboxStyle? = null + + /** + * Sets the style of the notification to [SystemNotificationStyle.BigTextStyle]. + * + * This style displays a large block of text. + * + * **Note:** A system notification can either have a BigText or InboxStyle, not both. + * + * @param text The text to be displayed in the notification. + */ + fun bigText(text: String) { + @Suppress("VisibleForTests") + bigText = BigTextStyle(text = text) + } + + /** + * Sets the style of the notification to [SystemNotificationStyle.InboxStyle]. + * + * This style is designed for aggregated notifications. + * + * **Note:** A system notification can either have a BigText or InboxStyle, not both. + * + * @param builder A lambda with [InboxSystemNotificationStyleBuilder] as its receiver, + * used to configure the Inbox style. + * @see InboxSystemNotificationStyleBuilder + */ + @NotificationStyleMarker + fun inbox(builder: @NotificationStyleMarker InboxSystemNotificationStyleBuilder.() -> Unit) { + inboxStyle = InboxSystemNotificationStyleBuilder().apply(builder).build() + } + + /** + * Builds and returns the configured [SystemNotificationStyle]. + * + * This method validates that either a [BigTextStyle] or an [InboxStyle] has been set, but not both. + * If both styles are set, or if neither style is set (which should be an unexpected state), + * it will throw an [IllegalStateException]. + * + * @return The configured [SystemNotificationStyle] which will be either a [BigTextStyle] or an [InboxStyle]. + * @throws IllegalStateException if both `bigText` and `inboxStyle` are set, or if neither are set. + */ + internal fun build(): SystemNotificationStyle { + // shadowing properties to safely capture its value at the call time. + val bigText = bigText + val inboxStyle = inboxStyle + return when { + bigText != null && inboxStyle != null -> error( + "A system notification can either have a BigText or InboxStyle, not both.", + ) + + bigText != null -> bigText + + inboxStyle != null -> inboxStyle + + else -> error("You must configure at least one of the following styles: bigText or inbox.") + } + } +} diff --git a/feature/notification/api/src/commonTest/kotlin/net/thunderbird/feature/notification/api/ui/style/InAppNotificationStyleTest.kt b/feature/notification/api/src/commonTest/kotlin/net/thunderbird/feature/notification/api/ui/style/InAppNotificationStyleTest.kt new file mode 100644 index 00000000000..0ec016ef667 --- /dev/null +++ b/feature/notification/api/src/commonTest/kotlin/net/thunderbird/feature/notification/api/ui/style/InAppNotificationStyleTest.kt @@ -0,0 +1,123 @@ +package net.thunderbird.feature.notification.api.ui.style + +import assertk.assertThat +import assertk.assertions.hasMessage +import assertk.assertions.isEqualTo +import assertk.assertions.isInstanceOf +import kotlin.test.Test +import kotlin.test.assertFails +import net.thunderbird.feature.notification.api.NotificationSeverity + +@Suppress("MaxLineLength") +class InAppNotificationStyleTest { + @Test + fun `inAppNotificationStyle dsl should create a fatal in-app notification style when NotificationSeverity Fatal is provided`() { + // Arrange + val expected = InAppNotificationStyle.Fatal + + // Act + val inAppStyle = inAppNotificationStyle { + severity(NotificationSeverity.Fatal) + } + + // Assert + assertThat(inAppStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `inAppNotificationStyle dsl should create a critical in-app notification style when NotificationSeverity Critical is provided`() { + // Arrange + val expected = InAppNotificationStyle.Critical + + // Act + val inAppStyle = inAppNotificationStyle { + severity(NotificationSeverity.Critical) + } + + // Assert + assertThat(inAppStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `inAppNotificationStyle dsl should create a temporary in-app notification style when NotificationSeverity Temporary is provided`() { + // Arrange + val expected = InAppNotificationStyle.Temporary + + // Act + val inAppStyle = inAppNotificationStyle { + severity(NotificationSeverity.Temporary) + } + + // Assert + assertThat(inAppStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `inAppNotificationStyle dsl should create a warning in-app notification style when NotificationSeverity Warning is provided`() { + // Arrange + val expected = InAppNotificationStyle.Warning + + // Act + val inAppStyle = inAppNotificationStyle { + severity(NotificationSeverity.Warning) + } + + // Assert + assertThat(inAppStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `inAppNotificationStyle dsl should create a information in-app notification style when NotificationSeverity Information is provided`() { + // Arrange + val expected = InAppNotificationStyle.Information + + // Act + val inAppStyle = inAppNotificationStyle { + severity(NotificationSeverity.Information) + } + + // Assert + assertThat(inAppStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `inAppNotificationStyle dsl should throw IllegalArgumentException when severity method is called multiple times within inAppNotification dsl`() { + // Arrange & Act + val exception = assertFails { + inAppNotificationStyle { + severity(severity = NotificationSeverity.Fatal) + severity(severity = NotificationSeverity.Critical) + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("In-App Notifications must have only one severity.") + } + + @Test + fun `inAppNotificationStyle dsl should throw IllegalStateException when in-app notification style is called without any style configuration`() { + // Arrange & Act + val exception = assertFails { + inAppNotificationStyle { + // intentionally empty. + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("You must add severity of the in-app notification.") + } +} diff --git a/feature/notification/api/src/commonTest/kotlin/net/thunderbird/feature/notification/api/ui/style/SystemNotificationStyleTest.kt b/feature/notification/api/src/commonTest/kotlin/net/thunderbird/feature/notification/api/ui/style/SystemNotificationStyleTest.kt new file mode 100644 index 00000000000..556c8b13bea --- /dev/null +++ b/feature/notification/api/src/commonTest/kotlin/net/thunderbird/feature/notification/api/ui/style/SystemNotificationStyleTest.kt @@ -0,0 +1,180 @@ +package net.thunderbird.feature.notification.api.ui.style + +import assertk.assertThat +import assertk.assertions.hasMessage +import assertk.assertions.isEqualTo +import assertk.assertions.isInstanceOf +import assertk.assertions.prop +import kotlin.test.Test +import kotlin.test.assertFails +import net.thunderbird.feature.notification.api.ui.style.builder.MAX_LINES + +@Suppress("MaxLineLength") +class SystemNotificationStyleTest { + @Test + fun `systemNotificationStyle dsl should create inbox system notification style`() { + // Arrange + val title = "The title" + val summary = "The summary" + val expected = SystemNotificationStyle.InboxStyle( + bigContentTitle = title, + summary = summary, + lines = listOf(), + ) + + // Act + val systemStyle = systemNotificationStyle { + inbox { + title(title) + summary(summary) + } + } + + // Assert + assertThat(systemStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `systemNotificationStyle dsl should create inbox system notification style with multiple lines`() { + // Arrange + val title = "The title" + val summary = "The summary" + val contentLines = List(size = 5) { + "line $it" + } + val expected = SystemNotificationStyle.InboxStyle( + bigContentTitle = title, + summary = summary, + lines = contentLines, + ) + + // Act + val systemStyle = systemNotificationStyle { + inbox { + title(title) + summary(summary) + for (line in contentLines) { + line(line) + } + } + } + + // Assert + assertThat(systemStyle) + .isInstanceOf() + .isEqualTo(expected) + } + + @Test + fun `systemNotificationStyle dsl should create big text system notification style`() { + // Arrange + val bigText = "The ${"big ".repeat(n = 1000)}text" + + // Act + val systemStyle = systemNotificationStyle { + bigText(bigText) + } + + // Assert + assertThat(systemStyle) + .isInstanceOf() + .prop("text") { it.text } + .isEqualTo(bigText) + } + + @Test + fun `systemNotificationStyle dsl should throw IllegalStateException when inbox system notification is missing title`() { + // Arrange & Act + val exception = assertFails { + systemNotificationStyle { + inbox { + summary("summary") + } + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("The inbox notification's title is required") + } + + @Test + fun `systemNotificationStyle dsl should throw IllegalStateException when inbox system notification is missing summary`() { + // Arrange & Act + val exception = assertFails { + systemNotificationStyle { + inbox { + title("title") + } + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("The inbox notification's summary is required") + } + + @Suppress("VisibleForTests") + @Test + fun `systemNotificationStyle dsl should throw IllegalArgumentException when inbox system notification adds more then 5 lines`() { + // Arrange + val lines = List(size = MAX_LINES + 1) { "line $it" } + + // Act + val exception = assertFails { + systemNotificationStyle { + inbox { + title("title") + summary("summary") + lines(lines = lines.toTypedArray()) + } + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("The maximum number of lines for a inbox notification is $MAX_LINES") + } + + @Test + fun `systemNotificationStyle dsl should throw IllegalStateException when system notification style set both big text and inbox styles`() { + // Arrange + val bigText = "The ${"big ".repeat(n = 1000)}text" + + // Act + val exception = assertFails { + systemNotificationStyle { + bigText(bigText) + inbox { + title("title") + summary("summary") + } + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("A system notification can either have a BigText or InboxStyle, not both.") + } + + @Test + fun `systemNotificationStyle dsl should throw IllegalStateException when system notification style is called without any style configuration`() { + // Arrange & Act + val exception = assertFails { + systemNotificationStyle { + // intentionally empty. + } + } + + // Assert + assertThat(exception) + .isInstanceOf() + .hasMessage("You must configure at least one of the following styles: bigText or inbox.") + } +}