diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index c8a8ee6f1f..5d7ac33e5e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -37,9 +37,8 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.textcomposer.aRichTextEditorState import io.element.android.libraries.textcomposer.model.MessageComposerMode -import io.element.android.libraries.textcomposer.model.TextEditorState +import io.element.android.libraries.textcomposer.model.aTextEditorStateRich import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf @@ -97,7 +96,7 @@ fun aMessagesState( roomAvatar: AsyncData = AsyncData.Success(AvatarData("!id:domain", "Room name", size = AvatarSize.TimelineRoom)), userEventPermissions: UserEventPermissions = aUserEventPermissions(), composerState: MessageComposerState = aMessageComposerState( - textEditorState = TextEditorState.Rich(aRichTextEditorState(initialText = "Hello", initialFocus = true)), + textEditorState = aTextEditorStateRich(initialText = "Hello", initialFocus = true), isFullScreen = false, mode = MessageComposerMode.Normal, ), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt index 1b57c52d23..c34f072c6d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/MessagesViewWithIdentityChangePreview.kt @@ -14,8 +14,7 @@ import io.element.android.features.messages.impl.aMessagesState import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState -import io.element.android.libraries.textcomposer.model.TextEditorState +import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown @PreviewsDayNight @Composable @@ -25,11 +24,9 @@ internal fun MessagesViewWithIdentityChangePreview( MessagesView( state = aMessagesState( composerState = aMessageComposerState( - textEditorState = TextEditorState.Markdown( - state = MarkdownTextEditorState( - initialText = "", - initialFocus = false, - ) + textEditorState = aTextEditorStateMarkdown( + initialText = "", + initialFocus = false, ) ), identityChangeState = identityChangeState, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt index 2730872072..a36102bc7d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerStateProvider.kt @@ -8,10 +8,10 @@ package io.element.android.features.messages.impl.messagecomposer import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.textcomposer.aRichTextEditorState import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.TextEditorState +import io.element.android.libraries.textcomposer.model.aTextEditorStateRich import io.element.android.wysiwyg.display.TextDisplay import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -24,7 +24,7 @@ open class MessageComposerStateProvider : PreviewParameterProvider = Presenter { aMessageComposerState( // Use TextEditorState.Markdown, so that we can request focus manually. - textEditorState = TextEditorState.Markdown(MarkdownTextEditorState(initialText = "", initialFocus = false)) + textEditorState = aTextEditorStateMarkdown(initialText = "", initialFocus = false) ) }, actionListEventSink: (ActionListEvents) -> Unit = {}, diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index f7b19f9d9a..cf98dd5741 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -57,7 +57,6 @@ import io.element.android.libraries.textcomposer.components.VoiceMessagePreview import io.element.android.libraries.textcomposer.components.VoiceMessageRecorderButton import io.element.android.libraries.textcomposer.components.VoiceMessageRecording import io.element.android.libraries.textcomposer.components.markdown.MarkdownTextInput -import io.element.android.libraries.textcomposer.components.markdown.aMarkdownTextEditorState import io.element.android.libraries.textcomposer.components.textInputRoundedCornerShape import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.libraries.textcomposer.model.Suggestion @@ -65,6 +64,8 @@ import io.element.android.libraries.textcomposer.model.TextEditorState import io.element.android.libraries.textcomposer.model.VoiceMessagePlayerEvent import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent import io.element.android.libraries.textcomposer.model.VoiceMessageState +import io.element.android.libraries.textcomposer.model.aTextEditorStateMarkdown +import io.element.android.libraries.textcomposer.model.aTextEditorStateRich import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.wysiwyg.compose.RichTextEditor import io.element.android.wysiwyg.compose.RichTextEditorState @@ -500,7 +501,7 @@ internal fun TextComposerSimplePreview() = ElementPreview { items = persistentListOf( { ATextComposer( - TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "", initialFocus = true)), + state = aTextEditorStateMarkdown(initialText = "", initialFocus = true), voiceMessageState = VoiceMessageState.Idle, composerMode = MessageComposerMode.Normal, enableVoiceMessages = true, @@ -508,7 +509,7 @@ internal fun TextComposerSimplePreview() = ElementPreview { }, { ATextComposer( - TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "A message", initialFocus = true)), + state = aTextEditorStateMarkdown(initialText = "A message", initialFocus = true), voiceMessageState = VoiceMessageState.Idle, composerMode = MessageComposerMode.Normal, enableVoiceMessages = true, @@ -516,11 +517,9 @@ internal fun TextComposerSimplePreview() = ElementPreview { }, { ATextComposer( - TextEditorState.Markdown( - aMarkdownTextEditorState( - initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow", - initialFocus = true - ) + state = aTextEditorStateMarkdown( + initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow", + initialFocus = true, ), voiceMessageState = VoiceMessageState.Idle, composerMode = MessageComposerMode.Normal, @@ -529,7 +528,7 @@ internal fun TextComposerSimplePreview() = ElementPreview { }, { ATextComposer( - TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "A message without focus", initialFocus = false)), + state = aTextEditorStateMarkdown(initialText = "A message without focus", initialFocus = false), voiceMessageState = VoiceMessageState.Idle, composerMode = MessageComposerMode.Normal, enableVoiceMessages = true, @@ -544,7 +543,7 @@ internal fun TextComposerSimplePreview() = ElementPreview { internal fun TextComposerFormattingPreview() = ElementPreview { PreviewColumn(items = persistentListOf({ ATextComposer( - TextEditorState.Rich(aRichTextEditorState()), + state = aTextEditorStateRich(), voiceMessageState = VoiceMessageState.Idle, showTextFormatting = true, composerMode = MessageComposerMode.Normal, @@ -552,7 +551,7 @@ internal fun TextComposerFormattingPreview() = ElementPreview { ) }, { ATextComposer( - TextEditorState.Rich(aRichTextEditorState(initialText = "A message")), + state = aTextEditorStateRich(initialText = "A message"), voiceMessageState = VoiceMessageState.Idle, showTextFormatting = true, composerMode = MessageComposerMode.Normal, @@ -560,10 +559,8 @@ internal fun TextComposerFormattingPreview() = ElementPreview { ) }, { ATextComposer( - TextEditorState.Rich( - aRichTextEditorState( - initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow", - ) + state = aTextEditorStateRich( + initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow", ), voiceMessageState = VoiceMessageState.Idle, showTextFormatting = true, @@ -578,7 +575,7 @@ internal fun TextComposerFormattingPreview() = ElementPreview { internal fun TextComposerEditPreview() = ElementPreview { PreviewColumn(items = persistentListOf({ ATextComposer( - TextEditorState.Rich(aRichTextEditorState(initialText = "A message", initialFocus = true)), + state = aTextEditorStateRich(initialText = "A message", initialFocus = true), voiceMessageState = VoiceMessageState.Idle, composerMode = aMessageComposerModeEdit(), enableVoiceMessages = true, @@ -591,7 +588,7 @@ internal fun TextComposerEditPreview() = ElementPreview { internal fun MarkdownTextComposerEditPreview() = ElementPreview { PreviewColumn(items = persistentListOf({ ATextComposer( - TextEditorState.Markdown(aMarkdownTextEditorState(initialText = "A message", initialFocus = true)), + state = aTextEditorStateMarkdown(initialText = "A message", initialFocus = true), voiceMessageState = VoiceMessageState.Idle, composerMode = aMessageComposerModeEdit(), enableVoiceMessages = true, @@ -603,7 +600,7 @@ internal fun MarkdownTextComposerEditPreview() = ElementPreview { @Composable internal fun TextComposerReplyPreview(@PreviewParameter(InReplyToDetailsProvider::class) inReplyToDetails: InReplyToDetails) = ElementPreview { ATextComposer( - state = TextEditorState.Rich(aRichTextEditorState()), + state = aTextEditorStateRich(), voiceMessageState = VoiceMessageState.Idle, composerMode = aMessageComposerModeReply( replyToDetails = inReplyToDetails, @@ -619,7 +616,7 @@ internal fun TextComposerVoicePreview() = ElementPreview { fun VoicePreview( voiceMessageState: VoiceMessageState ) = ATextComposer( - TextEditorState.Rich(aRichTextEditorState(initialFocus = true)), + state = aTextEditorStateRich(initialFocus = true), voiceMessageState = voiceMessageState, composerMode = MessageComposerMode.Normal, enableVoiceMessages = true, @@ -708,17 +705,6 @@ private fun ATextComposer( ) } -fun aRichTextEditorState( - initialText: String = "", - initialHtml: String = initialText, - initialMarkdown: String = initialText, - initialFocus: Boolean = false, -) = RichTextEditorState( - initialHtml = initialHtml, - initialMarkdown = initialMarkdown, - initialFocus = initialFocus, -) - fun aMessageComposerModeEdit( eventOrTransactionId: EventOrTransactionId = EventId("$1234").toEventOrTransactionId(), content: String = "Some text", diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt index ad14d40016..45150e0bd9 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/TextFormatting.kt @@ -26,7 +26,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.textcomposer.R import io.element.android.libraries.textcomposer.TextComposerLinkDialog -import io.element.android.libraries.textcomposer.aRichTextEditorState +import io.element.android.libraries.textcomposer.model.aRichTextEditorState import io.element.android.wysiwyg.compose.RichTextEditorState import io.element.android.wysiwyg.view.models.InlineFormat import io.element.android.wysiwyg.view.models.LinkAction diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt index 2c72c81cc4..6f451c7236 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt @@ -36,6 +36,7 @@ import io.element.android.libraries.textcomposer.mentions.updateMentionStyles import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState import io.element.android.libraries.textcomposer.model.Suggestion import io.element.android.libraries.textcomposer.model.SuggestionType +import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState import io.element.android.wysiwyg.compose.RichTextEditorStyle import io.element.android.wysiwyg.compose.internal.applyStyleInCompose @@ -78,8 +79,8 @@ fun MarkdownTextInput( AndroidView( modifier = Modifier - .padding(top = 6.dp, bottom = 6.dp) - .fillMaxWidth(), + .padding(top = 6.dp, bottom = 6.dp) + .fillMaxWidth(), factory = { context -> MarkdownEditText(context).apply { tag = TestTags.plainTextEditor.value // Needed for UI tests @@ -184,7 +185,7 @@ internal fun MarkdownTextInputPreview() { ElementPreview { val style = ElementRichTextEditorStyle.composerStyle(hasFocus = true) MarkdownTextInput( - state = aMarkdownTextEditorState(), + state = aMarkdownTextEditorState(initialText = "Hello, World!"), subcomposing = false, onTyping = {}, onReceiveSuggestion = {}, @@ -193,11 +194,3 @@ internal fun MarkdownTextInputPreview() { ) } } - -internal fun aMarkdownTextEditorState( - initialText: String = "Hello, World!", - initialFocus: Boolean = true, -) = MarkdownTextEditorState( - initialText = initialText, - initialFocus = initialFocus, -) diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/Fixtures.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/Fixtures.kt new file mode 100644 index 0000000000..c4afd3ea67 --- /dev/null +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/model/Fixtures.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.textcomposer.model + +import io.element.android.wysiwyg.compose.RichTextEditorState + +fun aTextEditorStateMarkdown( + initialText: String? = "", + initialFocus: Boolean = false, +): TextEditorState { + return TextEditorState.Markdown( + aMarkdownTextEditorState( + initialText = initialText, + initialFocus = initialFocus, + ) + ) +} + +fun aMarkdownTextEditorState( + initialText: String? = "", + initialFocus: Boolean = false, +): MarkdownTextEditorState { + return MarkdownTextEditorState( + initialText = initialText, + initialFocus = initialFocus, + ) +} + +fun aTextEditorStateRich( + initialText: String = "", + initialHtml: String = initialText, + initialMarkdown: String = initialText, + initialFocus: Boolean = false, +): TextEditorState { + return TextEditorState.Rich( + aRichTextEditorState( + initialText = initialText, + initialHtml = initialHtml, + initialMarkdown = initialMarkdown, + initialFocus = initialFocus, + ) + ) +} + +fun aRichTextEditorState( + initialText: String = "", + initialHtml: String = initialText, + initialMarkdown: String = initialText, + initialFocus: Boolean = false, +): RichTextEditorState { + return RichTextEditorState( + initialHtml = initialHtml, + initialMarkdown = initialMarkdown, + initialFocus = initialFocus, + ) +} diff --git a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt index c0a9612eab..66b7bf2e47 100644 --- a/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt +++ b/libraries/textcomposer/impl/src/test/kotlin/io/element/android/libraries/textcomposer/impl/model/MarkdownTextEditorStateTest.kt @@ -23,9 +23,9 @@ import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.textcomposer.mentions.MentionSpan import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion -import io.element.android.libraries.textcomposer.model.MarkdownTextEditorState import io.element.android.libraries.textcomposer.model.Suggestion import io.element.android.libraries.textcomposer.model.SuggestionType +import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState import org.junit.Test import org.junit.runner.RunWith @@ -33,7 +33,7 @@ import org.junit.runner.RunWith class MarkdownTextEditorStateTest { @Test fun `insertMention - room alias - getMentions return empty list`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true) + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true) val suggestion = aRoomAliasSuggestion() val permalinkBuilder = FakePermalinkBuilder() val mentionSpanProvider = aMentionSpanProvider() @@ -43,7 +43,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertSuggestion - room alias - with member but failed PermalinkBuilder result`() { - val state = MarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply { + val state = aMarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Room, text = "") } val suggestion = aRoomAliasSuggestion() @@ -55,7 +55,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertSuggestion - room alias`() { - val state = MarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply { + val state = aMarkdownTextEditorState(initialText = "Hello #", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Room, text = "") } val suggestion = aRoomAliasSuggestion() @@ -67,7 +67,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertSuggestion - with no currentMentionSuggestion does nothing`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true) + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true) val member = aRoomMember() val mention = ResolvedSuggestion.Member(member) val permalinkBuilder = FakePermalinkBuilder() @@ -80,7 +80,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertSuggestion - with member but failed PermalinkBuilder result`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply { + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Mention, text = "") } val member = aRoomMember() @@ -97,7 +97,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertSuggestion - with member`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply { + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Mention, text = "") } val member = aRoomMember() @@ -115,7 +115,7 @@ class MarkdownTextEditorStateTest { @Test fun `insertSuggestion - with @room`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply { + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true).apply { currentSuggestion = Suggestion(start = 6, end = 7, type = SuggestionType.Mention, text = "") } val mention = ResolvedSuggestion.AtRoom @@ -133,7 +133,7 @@ class MarkdownTextEditorStateTest { @Test fun `getMessageMarkdown - when there are no MentionSpans returns the same text`() { val text = "No mentions here" - val state = MarkdownTextEditorState(initialText = text, initialFocus = true) + val state = aMarkdownTextEditorState(initialText = text, initialFocus = true) val markdown = state.getMessageMarkdown(FakePermalinkBuilder()) @@ -147,7 +147,7 @@ class MarkdownTextEditorStateTest { permalinkForUserLambda = { Result.success("https://matrix.to/#/$it") }, permalinkForRoomAliasLambda = { Result.success("https://matrix.to/#/$it") }, ) - val state = MarkdownTextEditorState(initialText = text, initialFocus = true) + val state = aMarkdownTextEditorState(initialText = text, initialFocus = true) state.text.update(aMarkdownTextWithMentions(), needsDisplaying = false) val markdown = state.getMessageMarkdown(permalinkBuilder = permalinkBuilder) @@ -160,14 +160,14 @@ class MarkdownTextEditorStateTest { @Test fun `getMentions - when there are no MentionSpans returns empty list of mentions`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true) + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true) assertThat(state.getMentions()).isEmpty() } @Test fun `getMentions - when there are MentionSpans returns a list of mentions`() { - val state = MarkdownTextEditorState(initialText = "Hello @", initialFocus = true) + val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true) state.text.update(aMarkdownTextWithMentions(), needsDisplaying = false) val mentions = state.getMentions()