diff --git a/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/domain/model/event/Event.kt b/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/domain/model/event/Event.kt index b83d41a14..546ea3cb6 100644 --- a/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/domain/model/event/Event.kt +++ b/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/domain/model/event/Event.kt @@ -23,6 +23,7 @@ import com.infomaniak.multiplatform_calendar.core.domain.model.calendar.Calendar import com.infomaniak.multiplatform_calendar.core.domain.model.event.alarm.EventAlarm import com.infomaniak.multiplatform_calendar.core.domain.model.event.recurrence.RecurrenceScope import com.infomaniak.multiplatform_calendar.core.domain.model.event.recurrence.recurrenceScopesFor +import com.infomaniak.multiplatform_calendar.core.extensions.removeMarkedBlocks import kotlin.experimental.ExperimentalObjCRefinement import kotlin.native.HiddenFromObjC import kotlin.time.ExperimentalTime @@ -67,4 +68,9 @@ public data class Event( /** What a mutation of this event may be asked to reach, empty when there is nothing to ask. */ val recurrenceScopes: Set get() = recurrenceScopesFor(isOccurrence, canEdit) + + /** The description with all Infomaniak marked blocks removed. */ + val cleanedDescription: String + get() = description?.removeMarkedBlocks() ?: "" + } diff --git a/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/extensions/EventDescriptionExtensions.kt b/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/extensions/EventDescriptionExtensions.kt new file mode 100644 index 000000000..168e2417d --- /dev/null +++ b/CalendarCore/src/commonMain/kotlin/com/infomaniak/multiplatform_calendar/core/extensions/EventDescriptionExtensions.kt @@ -0,0 +1,25 @@ +/* + * Infomaniak Calendar - Multiplatform + * Copyright (C) 2026 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.multiplatform_calendar.core.extensions + +private const val MARKED_BLOCKS = "/\\*----------------------------------------\\*/" +private val MARKED_BLOCKS_REGEX = Regex("$MARKED_BLOCKS[\\s\\S]*?$MARKED_BLOCKS") + +internal fun String.removeMarkedBlocks(): String { + return this.replace(MARKED_BLOCKS_REGEX, "").trim() +} diff --git a/CalendarCore/src/commonTest/kotlin/com/infomaniak/multiplatform_calendar/core/extensions/EventDescriptionExtensionsTest.kt b/CalendarCore/src/commonTest/kotlin/com/infomaniak/multiplatform_calendar/core/extensions/EventDescriptionExtensionsTest.kt new file mode 100644 index 000000000..1c55d788c --- /dev/null +++ b/CalendarCore/src/commonTest/kotlin/com/infomaniak/multiplatform_calendar/core/extensions/EventDescriptionExtensionsTest.kt @@ -0,0 +1,106 @@ +/* + * Infomaniak Calendar - Multiplatform + * Copyright (C) 2026 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.multiplatform_calendar.core.extensions + +import kotlin.test.Test +import kotlin.test.assertEquals + +class EventDescriptionExtensionsTest { + + private val marker = "/*----------------------------------------*/" + + @Test + fun removeMarkedBlocks_removesOneBlockAndPreservesSurroundingText() { + val input = "before${marker}content to remove${marker}after" + + assertEquals("beforeafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesMultipleBlocks() { + val input = "before${marker}first${marker}middle${marker}second${marker}after" + + assertEquals("beforemiddleafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesMultilineBlockAndPreservesLineBreaksOutsideIt() { + val input = "before\n${marker}\nfirst line\nsecond line\n${marker}\nafter" + + assertEquals("before\n\nafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesSeveralMultilineBlocks() { + val input = "before\n${marker}\nfirst block\nspanning two lines\n${marker}\nbetween\n" + + "${marker}\nsecond block\nspanning two lines\n${marker}\nafter" + + assertEquals("before\n\nbetween\n\nafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesMultilineEmptyBlock() { + val input = "before\n${marker}\n${marker}\nafter" + + assertEquals("before\n\nafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesBlockWithEmptyContent() { + val input = "before${marker}${marker}after" + + assertEquals("beforeafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesSeveralEmptyBlocks() { + val input = "before${marker}${marker}${marker}${marker}after" + + assertEquals("beforeafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_removesEmptyAndNonEmptyBlocksTogether() { + val input = "before${marker}content${marker}${marker}${marker}after" + + assertEquals("beforeafter", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_returnsEmptyStringWhenOnlyAnEmptyBlockIsPresent() { + val input = "${marker}${marker}" + + assertEquals("", input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_leavesTextWithoutBlocksUntouched() { + val input = "normal description" + + assertEquals(input, input.removeMarkedBlocks()) + } + + @Test + fun removeMarkedBlocks_leavesUnmatchedMarkerUntouched() { + val input = "before${marker}content without closing marker" + + assertEquals(input, input.removeMarkedBlocks()) + } +} + +