Browse Source

Thread decoration: add "Reply in thread" context

pull/1298/head
ganfra 1 year ago
parent
commit
b36ea5cedf
  1. 4
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt
  2. 6
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt
  3. 1
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt
  4. 2
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
  5. 2
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt
  6. 2
      features/roomdetails/impl/src/main/res/values/localazy.xml
  7. 3
      libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/MessageComposerMode.kt
  8. 14
      libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt
  9. 17
      libraries/ui-strings/src/main/res/values/localazy.xml

4
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt

@ -209,7 +209,8 @@ class MessagesPresenter @AssistedInject constructor(
TimelineItemAction.Copy -> handleCopyContents(targetEvent) TimelineItemAction.Copy -> handleCopyContents(targetEvent)
TimelineItemAction.Redact -> handleActionRedact(targetEvent) TimelineItemAction.Redact -> handleActionRedact(targetEvent)
TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState) TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState)
TimelineItemAction.Reply -> handleActionReply(targetEvent, composerState) TimelineItemAction.Reply,
TimelineItemAction.ReplyInThread -> handleActionReply(targetEvent, composerState)
TimelineItemAction.Developer -> handleShowDebugInfoAction(targetEvent) TimelineItemAction.Developer -> handleShowDebugInfoAction(targetEvent)
TimelineItemAction.Forward -> handleForwardAction(targetEvent) TimelineItemAction.Forward -> handleForwardAction(targetEvent)
TimelineItemAction.ReportContent -> handleReportAction(targetEvent) TimelineItemAction.ReportContent -> handleReportAction(targetEvent)
@ -312,6 +313,7 @@ class MessagesPresenter @AssistedInject constructor(
is TimelineItemUnknownContent -> null is TimelineItemUnknownContent -> null
} }
val composerMode = MessageComposerMode.Reply( val composerMode = MessageComposerMode.Reply(
isThreaded = targetEvent.isThreaded,
senderName = targetEvent.safeSenderName, senderName = targetEvent.safeSenderName,
eventId = targetEvent.eventId, eventId = targetEvent.eventId,
attachmentThumbnailInfo = attachmentThumbnailInfo, attachmentThumbnailInfo = attachmentThumbnailInfo,

6
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt

@ -130,7 +130,11 @@ class ActionListPresenter @Inject constructor(
if (timelineItem.isRemote) { if (timelineItem.isRemote) {
// Can only reply or forward messages already uploaded to the server // Can only reply or forward messages already uploaded to the server
if (userCanSendMessage) { if (userCanSendMessage) {
add(TimelineItemAction.Reply) if (timelineItem.isThreaded) {
add(TimelineItemAction.ReplyInThread)
} else {
add(TimelineItemAction.Reply)
}
} }
add(TimelineItemAction.Forward) add(TimelineItemAction.Forward)
} }

1
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt

@ -32,6 +32,7 @@ sealed class TimelineItemAction(
data object Copy : TimelineItemAction(CommonStrings.action_copy, VectorIcons.Copy) data object Copy : TimelineItemAction(CommonStrings.action_copy, VectorIcons.Copy)
data object Redact : TimelineItemAction(CommonStrings.action_remove, VectorIcons.Delete, destructive = true) data object Redact : TimelineItemAction(CommonStrings.action_remove, VectorIcons.Delete, destructive = true)
data object Reply : TimelineItemAction(CommonStrings.action_reply, VectorIcons.Reply) data object Reply : TimelineItemAction(CommonStrings.action_reply, VectorIcons.Reply)
data object ReplyInThread : TimelineItemAction(CommonStrings.action_reply_in_thread, VectorIcons.Reply)
data object Edit : TimelineItemAction(CommonStrings.action_edit, VectorIcons.Edit) data object Edit : TimelineItemAction(CommonStrings.action_edit, VectorIcons.Edit)
data object Developer : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode) data object Developer : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode)
data object ReportContent : TimelineItemAction(CommonStrings.action_report_content, VectorIcons.ReportContent, destructive = true) data object ReportContent : TimelineItemAction(CommonStrings.action_report_content, VectorIcons.ReportContent, destructive = true)

2
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

@ -400,7 +400,7 @@ private fun MessageEventBubbleContent(
Icon(resourceId = R.drawable.ic_thread_decoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary) Icon(resourceId = R.drawable.ic_thread_decoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary)
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
Text( Text(
text = "Thread", text = stringResource(CommonStrings.common_thread),
style = ElementTheme.typography.fontBodyXsRegular, style = ElementTheme.typography.fontBodyXsRegular,
color = ElementTheme.colors.textPrimary, color = ElementTheme.colors.textPrimary,
) )

2
features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt

@ -598,7 +598,7 @@ fun anEditMode(
transactionId: TransactionId? = null, transactionId: TransactionId? = null,
) = MessageComposerMode.Edit(eventId, message, transactionId) ) = MessageComposerMode.Edit(eventId, message, transactionId)
fun aReplyMode() = MessageComposerMode.Reply(A_USER_NAME, null, AN_EVENT_ID, A_MESSAGE) fun aReplyMode() = MessageComposerMode.Reply(A_USER_NAME, null, false, AN_EVENT_ID, A_MESSAGE)
fun aQuoteMode() = MessageComposerMode.Quote(AN_EVENT_ID, A_MESSAGE) fun aQuoteMode() = MessageComposerMode.Quote(AN_EVENT_ID, A_MESSAGE)
private fun String.toMessage() = Message( private fun String.toMessage() = Message(

2
features/roomdetails/impl/src/main/res/values/localazy.xml

@ -30,11 +30,13 @@
<string name="screen_room_notification_settings_default_setting_footnote">"You can change it in your %1$s."</string> <string name="screen_room_notification_settings_default_setting_footnote">"You can change it in your %1$s."</string>
<string name="screen_room_notification_settings_default_setting_footnote_content_link">"global settings"</string> <string name="screen_room_notification_settings_default_setting_footnote_content_link">"global settings"</string>
<string name="screen_room_notification_settings_default_setting_title">"Default setting"</string> <string name="screen_room_notification_settings_default_setting_title">"Default setting"</string>
<string name="screen_room_notification_settings_edit_remove_setting">"Remove custom setting"</string>
<string name="screen_room_notification_settings_error_loading_settings">"An error occurred while loading notification settings."</string> <string name="screen_room_notification_settings_error_loading_settings">"An error occurred while loading notification settings."</string>
<string name="screen_room_notification_settings_error_restoring_default">"Failed restoring the default mode, please try again."</string> <string name="screen_room_notification_settings_error_restoring_default">"Failed restoring the default mode, please try again."</string>
<string name="screen_room_notification_settings_error_setting_mode">"Failed setting the mode, please try again."</string> <string name="screen_room_notification_settings_error_setting_mode">"Failed setting the mode, please try again."</string>
<string name="screen_room_notification_settings_mode_all_messages">"All messages"</string> <string name="screen_room_notification_settings_mode_all_messages">"All messages"</string>
<string name="screen_room_notification_settings_mode_mentions_and_keywords">"Mentions and Keywords only"</string> <string name="screen_room_notification_settings_mode_mentions_and_keywords">"Mentions and Keywords only"</string>
<string name="screen_room_notification_settings_room_custom_settings_title">"In this room, notify me for"</string>
<string name="screen_dm_details_block_alert_action">"Block"</string> <string name="screen_dm_details_block_alert_action">"Block"</string>
<string name="screen_dm_details_block_alert_description">"Blocked users won\'t be able to send you messages and all their messages will be hidden. You can unblock them anytime."</string> <string name="screen_dm_details_block_alert_description">"Blocked users won\'t be able to send you messages and all their messages will be hidden. You can unblock them anytime."</string>
<string name="screen_dm_details_block_user">"Block user"</string> <string name="screen_dm_details_block_user">"Block user"</string>

3
libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/MessageComposerMode.kt

@ -41,6 +41,7 @@ sealed interface MessageComposerMode : Parcelable {
class Reply( class Reply(
val senderName: String, val senderName: String,
val attachmentThumbnailInfo: AttachmentThumbnailInfo?, val attachmentThumbnailInfo: AttachmentThumbnailInfo?,
val isThreaded: Boolean,
override val eventId: EventId, override val eventId: EventId,
override val defaultContent: String override val defaultContent: String
) : Special(eventId, defaultContent) ) : Special(eventId, defaultContent)
@ -60,5 +61,5 @@ sealed interface MessageComposerMode : Parcelable {
get() = this is Reply get() = this is Reply
val inThread: Boolean val inThread: Boolean
get() = false // TODO get() = this is Reply && isThreaded
} }

14
libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt

@ -183,9 +183,13 @@ fun TextComposer(
if (composerMode is MessageComposerMode.Special) { if (composerMode is MessageComposerMode.Special) {
ComposerModeView(composerMode = composerMode, onResetComposerMode = onResetComposerMode) ComposerModeView(composerMode = composerMode, onResetComposerMode = onResetComposerMode)
} }
TextInput( TextInput(
state = state, state = state,
placeholder = if (composerMode.inThread) {
stringResource(id = CommonStrings.action_reply_in_thread)
} else {
stringResource(id = CommonStrings.rich_text_editor_composer_placeholder)
},
roundedCorners = roundedCorners, roundedCorners = roundedCorners,
bgColor = bgColor, bgColor = bgColor,
onError = onError, onError = onError,
@ -237,6 +241,7 @@ fun TextComposer(
@Composable @Composable
private fun TextInput( private fun TextInput(
state: RichTextEditorState, state: RichTextEditorState,
placeholder: String,
roundedCorners: RoundedCornerShape, roundedCorners: RoundedCornerShape,
bgColor: Color, bgColor: Color,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -262,7 +267,7 @@ private fun TextInput(
// Placeholder // Placeholder
if (state.messageHtml.isEmpty()) { if (state.messageHtml.isEmpty()) {
Text( Text(
stringResource(CommonStrings.common_message), placeholder,
style = defaultTypography.copy( style = defaultTypography.copy(
color = ElementTheme.colors.textDisabled, color = ElementTheme.colors.textDisabled,
), ),
@ -686,6 +691,7 @@ internal fun TextComposerReplyPreview() = ElementPreview {
canSendMessage = false, canSendMessage = false,
onSendMessage = {}, onSendMessage = {},
composerMode = MessageComposerMode.Reply( composerMode = MessageComposerMode.Reply(
isThreaded = false,
senderName = "Alice", senderName = "Alice",
eventId = EventId("$1234"), eventId = EventId("$1234"),
attachmentThumbnailInfo = null, attachmentThumbnailInfo = null,
@ -701,6 +707,7 @@ internal fun TextComposerReplyPreview() = ElementPreview {
canSendMessage = true, canSendMessage = true,
onSendMessage = {}, onSendMessage = {},
composerMode = MessageComposerMode.Reply( composerMode = MessageComposerMode.Reply(
isThreaded = true,
senderName = "Alice", senderName = "Alice",
eventId = EventId("$1234"), eventId = EventId("$1234"),
attachmentThumbnailInfo = AttachmentThumbnailInfo( attachmentThumbnailInfo = AttachmentThumbnailInfo(
@ -719,6 +726,7 @@ internal fun TextComposerReplyPreview() = ElementPreview {
canSendMessage = true, canSendMessage = true,
onSendMessage = {}, onSendMessage = {},
composerMode = MessageComposerMode.Reply( composerMode = MessageComposerMode.Reply(
isThreaded = false,
senderName = "Alice", senderName = "Alice",
eventId = EventId("$1234"), eventId = EventId("$1234"),
attachmentThumbnailInfo = AttachmentThumbnailInfo( attachmentThumbnailInfo = AttachmentThumbnailInfo(
@ -737,6 +745,7 @@ internal fun TextComposerReplyPreview() = ElementPreview {
canSendMessage = true, canSendMessage = true,
onSendMessage = {}, onSendMessage = {},
composerMode = MessageComposerMode.Reply( composerMode = MessageComposerMode.Reply(
isThreaded = false,
senderName = "Alice", senderName = "Alice",
eventId = EventId("$1234"), eventId = EventId("$1234"),
attachmentThumbnailInfo = AttachmentThumbnailInfo( attachmentThumbnailInfo = AttachmentThumbnailInfo(
@ -755,6 +764,7 @@ internal fun TextComposerReplyPreview() = ElementPreview {
canSendMessage = true, canSendMessage = true,
onSendMessage = {}, onSendMessage = {},
composerMode = MessageComposerMode.Reply( composerMode = MessageComposerMode.Reply(
isThreaded = false,
senderName = "Alice", senderName = "Alice",
eventId = EventId("$1234"), eventId = EventId("$1234"),
attachmentThumbnailInfo = AttachmentThumbnailInfo( attachmentThumbnailInfo = AttachmentThumbnailInfo(

17
libraries/ui-strings/src/main/res/values/localazy.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="Use_an_identity_server_to_invite_by_email.__default_Use_the_default____defaultIdentityServerName_s___default__or_manage_in__settings_Settings__settings_._web">"Use an identity server to invite by email. "<default>"Use the default (%(defaultIdentityServerName)s)"</default>" or manage in "<settings>"Settings"</settings>"."</string>
<string name="a11y_hide_password">"Hide password"</string> <string name="a11y_hide_password">"Hide password"</string>
<string name="a11y_notifications_mentions_only">"Mentions only"</string> <string name="a11y_notifications_mentions_only">"Mentions only"</string>
<string name="a11y_notifications_muted">"Muted"</string> <string name="a11y_notifications_muted">"Muted"</string>
@ -37,6 +36,8 @@
<string name="action_learn_more">"Learn more"</string> <string name="action_learn_more">"Learn more"</string>
<string name="action_leave">"Leave"</string> <string name="action_leave">"Leave"</string>
<string name="action_leave_room">"Leave room"</string> <string name="action_leave_room">"Leave room"</string>
<string name="action_manage_account">"Manage account"</string>
<string name="action_manage_devices">"Manage devices"</string>
<string name="action_next">"Next"</string> <string name="action_next">"Next"</string>
<string name="action_no">"No"</string> <string name="action_no">"No"</string>
<string name="action_not_now">"Not now"</string> <string name="action_not_now">"Not now"</string>
@ -47,6 +48,7 @@
<string name="action_react">"React"</string> <string name="action_react">"React"</string>
<string name="action_remove">"Remove"</string> <string name="action_remove">"Remove"</string>
<string name="action_reply">"Reply"</string> <string name="action_reply">"Reply"</string>
<string name="action_reply_in_thread">"Reply in thread"</string>
<string name="action_report_bug">"Report bug"</string> <string name="action_report_bug">"Report bug"</string>
<string name="action_report_content">"Report Content"</string> <string name="action_report_content">"Report Content"</string>
<string name="action_retry">"Retry"</string> <string name="action_retry">"Retry"</string>
@ -65,8 +67,12 @@
<string name="action_take_photo">"Take photo"</string> <string name="action_take_photo">"Take photo"</string>
<string name="action_view_source">"View Source"</string> <string name="action_view_source">"View Source"</string>
<string name="action_yes">"Yes"</string> <string name="action_yes">"Yes"</string>
<string name="call_foreground_service_channel_title_android">"Ongoing call"</string>
<string name="call_foreground_service_message_android">"Tap to return to the call"</string>
<string name="call_foreground_service_title_android">"☎ Call in progress"</string>
<string name="common_about">"About"</string> <string name="common_about">"About"</string>
<string name="common_acceptable_use_policy">"Acceptable use policy"</string> <string name="common_acceptable_use_policy">"Acceptable use policy"</string>
<string name="common_advanced_settings">"Advanced settings"</string>
<string name="common_analytics">"Analytics"</string> <string name="common_analytics">"Analytics"</string>
<string name="common_audio">"Audio"</string> <string name="common_audio">"Audio"</string>
<string name="common_bubbles">"Bubbles"</string> <string name="common_bubbles">"Bubbles"</string>
@ -85,6 +91,7 @@
<string name="common_forward_message">"Forward message"</string> <string name="common_forward_message">"Forward message"</string>
<string name="common_gif">"GIF"</string> <string name="common_gif">"GIF"</string>
<string name="common_image">"Image"</string> <string name="common_image">"Image"</string>
<string name="common_in_reply_to">"In reply to %1$s"</string>
<string name="common_invite_unknown_profile">"This Matrix ID can\'t be found, so the invite might not be received."</string> <string name="common_invite_unknown_profile">"This Matrix ID can\'t be found, so the invite might not be received."</string>
<string name="common_leaving_room">"Leaving room"</string> <string name="common_leaving_room">"Leaving room"</string>
<string name="common_link_copied_to_clipboard">"Link copied to clipboard"</string> <string name="common_link_copied_to_clipboard">"Link copied to clipboard"</string>
@ -99,15 +106,16 @@
<string name="common_password">"Password"</string> <string name="common_password">"Password"</string>
<string name="common_people">"People"</string> <string name="common_people">"People"</string>
<string name="common_permalink">"Permalink"</string> <string name="common_permalink">"Permalink"</string>
<string name="common_poll_final_votes">"Final votes: %1$s"</string>
<string name="common_poll_total_votes">"Total votes: %1$s"</string> <string name="common_poll_total_votes">"Total votes: %1$s"</string>
<string name="common_poll_undisclosed_text">"Results will show after the poll has ended"</string> <string name="common_poll_undisclosed_text">"Results will show after the poll has ended"</string>
<string name="common_privacy_policy">"Privacy policy"</string> <string name="common_privacy_policy">"Privacy policy"</string>
<string name="common_reaction">"Reaction"</string>
<string name="common_reactions">"Reactions"</string> <string name="common_reactions">"Reactions"</string>
<string name="common_refreshing">"Refreshing…"</string> <string name="common_refreshing">"Refreshing…"</string>
<string name="common_replying_to">"Replying to %1$s"</string> <string name="common_replying_to">"Replying to %1$s"</string>
<string name="common_report_a_bug">"Report a bug"</string> <string name="common_report_a_bug">"Report a bug"</string>
<string name="common_report_submitted">"Report submitted"</string> <string name="common_report_submitted">"Report submitted"</string>
<string name="common_rich_text_editor">"Rich text editor"</string>
<string name="common_room_name">"Room name"</string> <string name="common_room_name">"Room name"</string>
<string name="common_room_name_placeholder">"e.g. your project name"</string> <string name="common_room_name_placeholder">"e.g. your project name"</string>
<string name="common_search_for_someone">"Search for someone"</string> <string name="common_search_for_someone">"Search for someone"</string>
@ -126,6 +134,7 @@
<string name="common_syncing">"Syncing"</string> <string name="common_syncing">"Syncing"</string>
<string name="common_text">"Text"</string> <string name="common_text">"Text"</string>
<string name="common_third_party_notices">"Third-party notices"</string> <string name="common_third_party_notices">"Third-party notices"</string>
<string name="common_thread">"Thread"</string>
<string name="common_topic">"Topic"</string> <string name="common_topic">"Topic"</string>
<string name="common_topic_placeholder">"What is this room about?"</string> <string name="common_topic_placeholder">"What is this room about?"</string>
<string name="common_unable_to_decrypt">"Unable to decrypt"</string> <string name="common_unable_to_decrypt">"Unable to decrypt"</string>
@ -162,10 +171,6 @@
<string name="leave_room_alert_private_subtitle">"Are you sure that you want to leave this room? This room is not public and you won\'t be able to rejoin without an invite."</string> <string name="leave_room_alert_private_subtitle">"Are you sure that you want to leave this room? This room is not public and you won\'t be able to rejoin without an invite."</string>
<string name="leave_room_alert_subtitle">"Are you sure that you want to leave the room?"</string> <string name="leave_room_alert_subtitle">"Are you sure that you want to leave the room?"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string> <string name="login_initial_device_name_android">"%1$s Android"</string>
<plurals name="__count_s_rooms_web">
<item quantity="one">"%(count)s room"</item>
<item quantity="other">"%(count)s rooms"</item>
</plurals>
<plurals name="common_member_count"> <plurals name="common_member_count">
<item quantity="one">"%1$d member"</item> <item quantity="one">"%1$d member"</item>
<item quantity="other">"%1$d members"</item> <item quantity="other">"%1$d members"</item>

Loading…
Cancel
Save