Merge branch 'main' into wallet
# Conflicts: # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNavigator.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsPickerView.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt # features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/topbars/MessagesViewTopBar.kt # libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/mentions/ResolvedSuggestion.kt
This commit is contained in:
commit
0ef6b69a79
912 changed files with 17051 additions and 4425 deletions
|
|
@ -134,7 +134,7 @@ private fun ReplyToModeView(
|
|||
modifier
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(ElementTheme.colors.bgCanvasDefault)
|
||||
.border(1.dp, ElementTheme.colors.borderInteractiveSecondary, RoundedCornerShape(6.dp))
|
||||
.border(1.dp, ElementTheme.colors.separatorPrimary, RoundedCornerShape(6.dp))
|
||||
.padding(4.dp)
|
||||
) {
|
||||
InReplyToView(
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.slashcommands.api.SlashCommandSuggestion
|
||||
|
||||
@Immutable
|
||||
sealed interface ResolvedSuggestion {
|
||||
|
|
@ -33,11 +34,7 @@ sealed interface ResolvedSuggestion {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A slash command suggestion (e.g., /pay).
|
||||
*/
|
||||
data class Command(
|
||||
val command: String,
|
||||
val description: String,
|
||||
val command: SlashCommandSuggestion,
|
||||
) : ResolvedSuggestion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,21 +61,29 @@ class MarkdownTextEditorState(
|
|||
}
|
||||
is ResolvedSuggestion.Member -> {
|
||||
val currentText = SpannableStringBuilder(text.value())
|
||||
val mentionSpan = mentionSpanProvider.createUserMentionSpan(resolvedSuggestion.roomMember.userId)
|
||||
val userId = resolvedSuggestion.roomMember.userId
|
||||
val mentionSpan = mentionSpanProvider.createUserMentionSpan(userId)
|
||||
currentText.replace(suggestion.start, suggestion.end, "@ ")
|
||||
val end = suggestion.start + 1
|
||||
currentText.setSpan(mentionSpan, suggestion.start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
this.text.update(currentText, true)
|
||||
this.selection = IntRange(end + 1, end + 1)
|
||||
text.update(currentText, true)
|
||||
selection = IntRange(end + 1, end + 1)
|
||||
}
|
||||
is ResolvedSuggestion.Alias -> {
|
||||
val currentText = SpannableStringBuilder(text.value())
|
||||
val mentionSpan = mentionSpanProvider.createRoomMentionSpan(resolvedSuggestion.roomAlias.toRoomIdOrAlias())
|
||||
val roomAlias = resolvedSuggestion.roomAlias
|
||||
val mentionSpan = mentionSpanProvider.createRoomMentionSpan(roomAlias.toRoomIdOrAlias())
|
||||
currentText.replace(suggestion.start, suggestion.end, "# ")
|
||||
val end = suggestion.start + 1
|
||||
currentText.setSpan(mentionSpan, suggestion.start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
this.text.update(currentText, true)
|
||||
this.selection = IntRange(end + 1, end + 1)
|
||||
text.update(currentText, true)
|
||||
selection = IntRange(end + 1, end + 1)
|
||||
}
|
||||
is ResolvedSuggestion.Command -> {
|
||||
// Just insert the command text
|
||||
text.update("${resolvedSuggestion.command.command} ", true)
|
||||
val length = resolvedSuggestion.command.command.length + 1
|
||||
selection = IntRange(length, length)
|
||||
}
|
||||
is ResolvedSuggestion.Command -> {
|
||||
// Insert the command text with a trailing space
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="rich_text_editor_a11y_add_attachment">"添付ファイルを追加"</string>
|
||||
<string name="rich_text_editor_bullet_list">"箇条リスト"</string>
|
||||
<string name="rich_text_editor_close_formatting_options">"書式設定を中止して閉じる"</string>
|
||||
<string name="rich_text_editor_code_block">"コードブロックを切替"</string>
|
||||
<string name="rich_text_editor_composer_caption_placeholder">"キャプションを追加"</string>
|
||||
<string name="rich_text_editor_composer_encrypted_placeholder">"暗号化されたメッセージ…"</string>
|
||||
<string name="rich_text_editor_composer_placeholder">"メッセージ…"</string>
|
||||
<string name="rich_text_editor_composer_unencrypted_placeholder">"暗号化されていないメッセージ…"</string>
|
||||
<string name="rich_text_editor_create_link">"リンクを作成"</string>
|
||||
<string name="rich_text_editor_edit_link">"リンクを編集"</string>
|
||||
<string name="rich_text_editor_format_action">"%1$s の状態: %2$s"</string>
|
||||
<string name="rich_text_editor_format_bold">"太字"</string>
|
||||
<string name="rich_text_editor_format_italic">"斜体"</string>
|
||||
<string name="rich_text_editor_format_state_disabled">"無効"</string>
|
||||
<string name="rich_text_editor_format_state_off">"オフ"</string>
|
||||
<string name="rich_text_editor_format_state_on">"オン"</string>
|
||||
<string name="rich_text_editor_format_strikethrough">"取り消し線を追加"</string>
|
||||
<string name="rich_text_editor_format_underline">"下線を追加"</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">"全画面モードの切替"</string>
|
||||
<string name="rich_text_editor_indent">"インデント"</string>
|
||||
<string name="rich_text_editor_inline_code">"コード部の書式"</string>
|
||||
<string name="rich_text_editor_link">"リンクを設定"</string>
|
||||
<string name="rich_text_editor_numbered_list">"番号リスト"</string>
|
||||
<string name="rich_text_editor_open_compose_options">"記述設定を開く"</string>
|
||||
<string name="rich_text_editor_quote">"引用の表示切替"</string>
|
||||
<string name="rich_text_editor_remove_link">"リンクを削除"</string>
|
||||
<string name="rich_text_editor_unindent">"インデントを削除"</string>
|
||||
<string name="rich_text_editor_url_placeholder">"リンク"</string>
|
||||
<string name="screen_media_upload_preview_caption_warning">"古いアプリケーションを使用しているユーザーはキャプションを見られない可能性があります。"</string>
|
||||
<string name="screen_room_voice_message_tooltip">"長押しで録音"</string>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="rich_text_editor_a11y_add_attachment">"Thêm tệp đính kèm"</string>
|
||||
<string name="rich_text_editor_bullet_list">"Chuyển đổi danh sách dấu đầu dòng"</string>
|
||||
<string name="rich_text_editor_close_formatting_options">"Hủy và đóng định dạng văn bản"</string>
|
||||
<string name="rich_text_editor_code_block">"Bật/tắt khối mã"</string>
|
||||
<string name="rich_text_editor_composer_placeholder">"Tin nhắn…"</string>
|
||||
<string name="rich_text_editor_create_link">"Tạo liên kết"</string>
|
||||
<string name="rich_text_editor_edit_link">"Sửa liên kết"</string>
|
||||
<string name="rich_text_editor_format_bold">"Áp dụng định dạng in đậm"</string>
|
||||
<string name="rich_text_editor_format_italic">"Áp dụng định dạng in nghiêng"</string>
|
||||
<string name="rich_text_editor_format_strikethrough">"Áp dụng định dạng gạch ngang"</string>
|
||||
<string name="rich_text_editor_format_underline">"Áp dụng định dạng gạch chân"</string>
|
||||
<string name="rich_text_editor_full_screen_toggle">"Bật/tắt chế độ toàn màn hình"</string>
|
||||
<string name="rich_text_editor_indent">"Thụt lề"</string>
|
||||
<string name="rich_text_editor_inline_code">"Áp dụng định dạng mã trong dòng"</string>
|
||||
<string name="rich_text_editor_link">"Đặt liên kết"</string>
|
||||
<string name="rich_text_editor_numbered_list">"Chuyển đổi danh sách được đánh số"</string>
|
||||
<string name="rich_text_editor_open_compose_options">"Mở tùy chọn soạn tin"</string>
|
||||
<string name="rich_text_editor_quote">"Chuyển sang Trích dẫn"</string>
|
||||
<string name="rich_text_editor_remove_link">"Xóa liên kết"</string>
|
||||
<string name="rich_text_editor_unindent">"Bỏ thụt lề"</string>
|
||||
<string name="rich_text_editor_url_placeholder">"Liên kết"</string>
|
||||
<string name="screen_room_voice_message_tooltip">"Nhấn giữ để ghi âm"</string>
|
||||
</resources>
|
||||
|
|
@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
|
||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import io.element.android.libraries.slashcommands.api.SlashCommandSuggestion
|
||||
import io.element.android.libraries.textcomposer.impl.mentions.aMentionSpanProvider
|
||||
import io.element.android.libraries.textcomposer.mentions.MentionSpan
|
||||
import io.element.android.libraries.textcomposer.mentions.MentionType
|
||||
|
|
@ -42,6 +43,7 @@ class MarkdownTextEditorStateTest {
|
|||
val mentionSpanProvider = aMentionSpanProvider()
|
||||
state.insertSuggestion(suggestion, mentionSpanProvider)
|
||||
assertThat(state.getMentions()).isEmpty()
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello @")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -53,6 +55,7 @@ class MarkdownTextEditorStateTest {
|
|||
val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) })
|
||||
val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
|
||||
state.insertSuggestion(suggestion, mentionSpanProvider)
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello # ")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -64,6 +67,19 @@ class MarkdownTextEditorStateTest {
|
|||
val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) })
|
||||
val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
|
||||
state.insertSuggestion(suggestion, mentionSpanProvider)
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello # ")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `insertSuggestion - command`() {
|
||||
val state = aMarkdownTextEditorState(initialText = "/rai", initialFocus = true).apply {
|
||||
currentSuggestion = Suggestion(start = 0, end = 3, type = SuggestionType.Command, text = "/rainbow")
|
||||
}
|
||||
val suggestion = aSlashCommandSuggestion()
|
||||
val permalinkParser = FakePermalinkParser(result = { PermalinkData.RoomLink(A_ROOM_ALIAS.toRoomIdOrAlias()) })
|
||||
val mentionSpanProvider = aMentionSpanProvider(permalinkParser = permalinkParser)
|
||||
state.insertSuggestion(suggestion, mentionSpanProvider)
|
||||
assertThat(state.text.value().toString()).isEqualTo("/rainbow ")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -74,6 +90,7 @@ class MarkdownTextEditorStateTest {
|
|||
val mentionSpanProvider = aMentionSpanProvider()
|
||||
state.insertSuggestion(mention, mentionSpanProvider)
|
||||
assertThat(state.getMentions()).isEmpty()
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello @")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -91,6 +108,7 @@ class MarkdownTextEditorStateTest {
|
|||
val mentions = state.getMentions()
|
||||
assertThat(mentions).isNotEmpty()
|
||||
assertThat((mentions.firstOrNull() as? IntentionalMention.User)?.userId).isEqualTo(member.userId)
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello @ ")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -107,15 +125,14 @@ class MarkdownTextEditorStateTest {
|
|||
val mentions = state.getMentions()
|
||||
assertThat(mentions).isNotEmpty()
|
||||
assertThat(mentions.firstOrNull()).isInstanceOf(IntentionalMention.Room::class.java)
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello @ ")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getMessageMarkdown - when there are no MentionSpans returns the same text`() {
|
||||
val text = "No mentions here"
|
||||
val state = aMarkdownTextEditorState(initialText = text, initialFocus = true)
|
||||
|
||||
val markdown = state.getMessageMarkdown(FakePermalinkBuilder())
|
||||
|
||||
assertThat(markdown).isEqualTo(text)
|
||||
}
|
||||
|
||||
|
|
@ -128,19 +145,17 @@ class MarkdownTextEditorStateTest {
|
|||
)
|
||||
val state = aMarkdownTextEditorState(initialText = text, initialFocus = true)
|
||||
state.text.update(aMarkdownTextWithMentions(), needsDisplaying = false)
|
||||
|
||||
val markdown = state.getMessageMarkdown(permalinkBuilder = permalinkBuilder)
|
||||
|
||||
assertThat(markdown).isEqualTo(
|
||||
"Hello [@alice:matrix.org](https://matrix.to/#/@alice:matrix.org) and everyone in @room" +
|
||||
" and a room [#room:domain.org](https://matrix.to/#/#room:domain.org)"
|
||||
)
|
||||
assertThat(state.text.value().toString()).isEqualTo("Hello @ and everyone in @ and a room #room:domain.org")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getMentions - when there are no MentionSpans returns empty list of mentions`() {
|
||||
val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true)
|
||||
|
||||
assertThat(state.getMentions()).isEmpty()
|
||||
}
|
||||
|
||||
|
|
@ -148,9 +163,7 @@ class MarkdownTextEditorStateTest {
|
|||
fun `getMentions - when there are MentionSpans returns a list of mentions`() {
|
||||
val state = aMarkdownTextEditorState(initialText = "Hello @", initialFocus = true)
|
||||
state.text.update(aMarkdownTextWithMentions(), needsDisplaying = false)
|
||||
|
||||
val mentions = state.getMentions()
|
||||
|
||||
assertThat(mentions).isNotEmpty()
|
||||
assertThat((mentions.firstOrNull() as? IntentionalMention.User)?.userId?.value).isEqualTo("@alice:matrix.org")
|
||||
assertThat(mentions.lastOrNull()).isInstanceOf(IntentionalMention.Room::class.java)
|
||||
|
|
@ -184,4 +197,14 @@ class MarkdownTextEditorStateTest {
|
|||
roomAvatarUrl = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun aSlashCommandSuggestion(): ResolvedSuggestion.Command {
|
||||
return ResolvedSuggestion.Command(
|
||||
command = SlashCommandSuggestion(
|
||||
command = "/rainbow",
|
||||
parameters = "param",
|
||||
description = "Make the text colorful 🌈",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue