From 3bd2b24b100253b659f77f5db6c4b2b0f4d841f9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Jun 2020 13:14:37 +0200 Subject: [PATCH 1/3] Use "you" instead of display name when the current user has sent the event. --- CHANGES.md | 2 +- .../src/main/res/values/strings.xml | 61 ++++ .../factory/MergedHeaderItemFactory.kt | 7 +- .../timeline/format/NoticeEventFormatter.kt | 306 ++++++++++++++---- .../timeline/item/MergedRoomCreationItem.kt | 11 +- vector/src/main/res/values/strings.xml | 4 + 6 files changed, 323 insertions(+), 68 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2bf7453632..ef31216264 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,7 @@ Features ✨: - Improvements 🙌: - - + - New wording for notice when current user is the sender Bugfix 🐛: - Switch theme is not fully taken into account without restarting the app diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index 69907e5835..b407ca8eba 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -2,53 +2,85 @@ %1$s: %2$s %1$s sent an image. + You sent an image. %1$s sent a sticker. + You sent a sticker. %s\'s invitation + Your invitation %1$s created the room + You created the room %1$s invited %2$s + You invited %1$s %1$s invited you %1$s joined the room + You joined the room %1$s left the room + You left the room %1$s rejected the invitation + You rejected the invitation %1$s kicked %2$s + You kicked %1$s %1$s unbanned %2$s + You unbanned %1$s %1$s banned %2$s + You banned %1$s %1$s withdrew %2$s\'s invitation + You withdrew %1$s\'s invitation %1$s changed their avatar + You changed your avatar %1$s set their display name to %2$s + You set your display name to %1$s %1$s changed their display name from %2$s to %3$s + You changed their display name from %1$s to %2$s %1$s removed their display name (%2$s) + You removed your display name (%1$s) %1$s changed the topic to: %2$s + You changed the topic to: %1$s %1$s changed the room name to: %2$s + You changed the room name to: %1$s %s placed a video call. + You placed a video call. %s placed a voice call. + You placed a voice call. %s answered the call. + You answered the call. %s ended the call. + You ended the call. %1$s made future room history visible to %2$s + You made future room history visible to %1$s all room members, from the point they are invited. all room members, from the point they joined. all room members. anyone. unknown (%s). %1$s turned on end-to-end encryption (%2$s) + You turned on end-to-end encryption (%1$s) %s upgraded this room. + You upgraded this room. %1$s requested a VoIP conference + You requested a VoIP conference VoIP conference started VoIP conference finished (avatar was changed too) %1$s removed the room name + You removed the room name %1$s removed the room topic + You removed the room topic Message removed Message removed by %1$s Message removed [reason: %1$s] Message removed by %1$s [reason: %2$s] %1$s updated their profile %2$s + You updated your profile %2$s %1$s sent an invitation to %2$s to join the room + You sent an invitation to %1$s to join the room %1$s revoked the invitation for %2$s to join the room + You revoked the invitation for %1$s to join the room %1$s accepted the invitation for %2$s + You accepted the invitation for %1$s ** Unable to decrypt: %s ** The sender\'s device has not sent us the keys for this message. @@ -245,39 +277,68 @@ Clear sending queue %1$s\'s invitation. Reason: %2$s + Your invitation. Reason: %2$s %1$s invited %2$s. Reason: %3$s + You invited %1$s. Reason: %2$s %1$s invited you. Reason: %2$s %1$s joined the room. Reason: %2$s + You joined the room. Reason: %1$s %1$s left the room. Reason: %2$s + You left the room. Reason: %1$s %1$s rejected the invitation. Reason: %2$s + You rejected the invitation. Reason: %1$s %1$s kicked %2$s. Reason: %3$s + You kicked %1$s. Reason: %2$s %1$s unbanned %2$s. Reason: %3$s + You unbanned %1$s. Reason: %2$s %1$s banned %2$s. Reason: %3$s + You banned %1$s. Reason: %2$s %1$s sent an invitation to %2$s to join the room. Reason: %3$s + You sent an invitation to %1$s to join the room. Reason: %2$s %1$s revoked the invitation for %2$s to join the room. Reason: %3$s + You revoked the invitation for %1$s to join the room. Reason: %2$s %1$s accepted the invitation for %2$s. Reason: %3$s + You accepted the invitation for %1$s. Reason: %2$s %1$s withdrew %2$s\'s invitation. Reason: %3$s + You withdrew %1$s\'s invitation. Reason: %2$s %1$s added %2$s as an address for this room. %1$s added %2$s as addresses for this room. + + You added %1$s as an address for this room. + You added %1$s as addresses for this room. + + %1$s removed %2$s as an address for this room. %1$s removed %3$s as addresses for this room. + + You removed %1$s as an address for this room. + You removed %2$s as addresses for this room. + + %1$s added %2$s and removed %3$s as addresses for this room. + You added %1$s and removed %2$s as addresses for this room. "%1$s set the main address for this room to %2$s." + "You set the main address for this room to %1$s." "%1$s removed the main address for this room." + "You removed the main address for this room." "%1$s has allowed guests to join the room." + "You have allowed guests to join the room." "%1$s has prevented guests from joining the room." + "You have prevented guests from joining the room." %1$s turned on end-to-end encryption. + You turned on end-to-end encryption. %1$s turned on end-to-end encryption (unrecognised algorithm %2$s). + You turned on end-to-end encryption (unrecognised algorithm %1$s). %s is requesting to verify your key, but your client does not support in-chat key verification. You will need to use legacy key verification to verify keys. diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt index 419fd673d1..6616025110 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt @@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.room.model.create.RoomCreateContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent +import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.extensions.prevOrNull import im.vector.riotx.features.home.AvatarRenderer import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController @@ -38,7 +39,8 @@ import im.vector.riotx.features.home.room.detail.timeline.item.MergedRoomCreatio import javax.inject.Inject class MergedHeaderItemFactory @Inject constructor(private val avatarRenderer: AvatarRenderer, - private val avatarSizeProvider: AvatarSizeProvider) { + private val avatarSizeProvider: AvatarSizeProvider, + private val activeSessionHolder: ActiveSessionHolder) { private val collapsedEventIds = linkedSetOf() private val mergeItemCollapseStates = HashMap() @@ -188,7 +190,8 @@ class MergedHeaderItemFactory @Inject constructor(private val avatarRenderer: Av }, hasEncryptionEvent = hasEncryption, isEncryptionAlgorithmSecure = encryptionAlgorithm == MXCRYPTO_ALGORITHM_MEGOLM, - readReceiptsCallback = callback + readReceiptsCallback = callback, + currentUserId = activeSessionHolder.getSafeActiveSession()?.myUserId ?: "" ) MergedRoomCreationItem_() .id(mergeId) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt index cab5b30190..5d6f65317d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt @@ -45,6 +45,8 @@ import javax.inject.Inject class NoticeEventFormatter @Inject constructor(private val sessionHolder: ActiveSessionHolder, private val sp: StringProvider) { + private fun Event.isSentByCurrentUser() = senderId != null && senderId == sessionHolder.getSafeActiveSession()?.myUserId + fun format(timelineEvent: TimelineEvent): CharSequence? { return when (val type = timelineEvent.root.getClearType()) { EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) @@ -57,7 +59,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active EventType.STATE_ROOM_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_GUEST_ACCESS -> formatRoomGuestAccessEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.STATE_ROOM_ENCRYPTION -> formatRoomEncryptionEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) - EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.senderInfo.disambiguatedDisplayName) + EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) EventType.CALL_INVITE, EventType.CALL_HANGUP, EventType.CALL_ANSWER -> formatCallEvent(type, timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName) @@ -88,7 +90,7 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active EventType.CALL_INVITE, EventType.CALL_HANGUP, EventType.CALL_ANSWER -> formatCallEvent(type, event, senderName) - EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(senderName) + EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(event, senderName) else -> { Timber.v("Type $type not handled by this formatter") null @@ -103,28 +105,54 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active private fun formatRoomCreateEvent(event: Event): CharSequence? { return event.getClearContent().toModel() ?.takeIf { it.creator.isNullOrBlank().not() } - ?.let { sp.getString(R.string.notice_room_created, it.creator) } + ?.let { + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_created_by_you) + } else { + sp.getString(R.string.notice_room_created, it.creator) + } + } } private fun formatRoomNameEvent(event: Event, senderName: String?): CharSequence? { val content = event.getClearContent().toModel() ?: return null return if (content.name.isNullOrBlank()) { - sp.getString(R.string.notice_room_name_removed, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_name_removed_by_you) + } else { + sp.getString(R.string.notice_room_name_removed, senderName) + } } else { - sp.getString(R.string.notice_room_name_changed, senderName, content.name) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_name_changed_by_you, content.name) + } else { + sp.getString(R.string.notice_room_name_changed, senderName, content.name) + } } } - private fun formatRoomTombstoneEvent(senderName: String?): CharSequence? { - return sp.getString(R.string.notice_room_update, senderName) + private fun formatRoomTombstoneEvent(event: Event, senderName: String?): CharSequence? { + return if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_update_by_you) + } else { + sp.getString(R.string.notice_room_update, senderName) + } } private fun formatRoomTopicEvent(event: Event, senderName: String?): CharSequence? { val content = event.getClearContent().toModel() ?: return null return if (content.topic.isNullOrEmpty()) { - sp.getString(R.string.notice_room_topic_removed, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_topic_removed_by_you) + } else { + sp.getString(R.string.notice_room_topic_removed, senderName) + } } else { - sp.getString(R.string.notice_room_topic_changed, senderName, content.topic) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_topic_changed_by_you, content.topic) + } else { + sp.getString(R.string.notice_room_topic_changed, senderName, content.topic) + } } } @@ -137,7 +165,11 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active RoomHistoryVisibility.JOINED -> sp.getString(R.string.notice_room_visibility_joined) RoomHistoryVisibility.WORLD_READABLE -> sp.getString(R.string.notice_room_visibility_world_readable) } - return sp.getString(R.string.notice_made_future_room_visibility, senderName, formattedVisibility) + return if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_made_future_room_visibility_by_you, formattedVisibility) + } else { + sp.getString(R.string.notice_made_future_room_visibility, senderName, formattedVisibility) + } } private fun formatCallEvent(type: String, event: Event, senderName: String?): CharSequence? { @@ -146,13 +178,29 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active val content = event.getClearContent().toModel() ?: return null val isVideoCall = content.offer.sdp == CallInviteContent.Offer.SDP_VIDEO return if (isVideoCall) { - sp.getString(R.string.notice_placed_video_call, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_placed_video_call_by_you) + } else { + sp.getString(R.string.notice_placed_video_call, senderName) + } } else { - sp.getString(R.string.notice_placed_voice_call, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_placed_voice_call_by_you) + } else { + sp.getString(R.string.notice_placed_voice_call, senderName) + } } } - EventType.CALL_ANSWER -> sp.getString(R.string.notice_answered_call, senderName) - EventType.CALL_HANGUP -> sp.getString(R.string.notice_ended_call, senderName) + EventType.CALL_ANSWER -> if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_answered_call_by_you) + } else { + sp.getString(R.string.notice_answered_call, senderName) + } + EventType.CALL_HANGUP -> if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_ended_call_by_you) + } else { + sp.getString(R.string.notice_ended_call, senderName) + } else -> null } } @@ -176,11 +224,23 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active val removedAliases = prevEventContent?.aliases.orEmpty() - eventContent?.aliases.orEmpty() return if (addedAliases.isNotEmpty() && removedAliases.isNotEmpty()) { - sp.getString(R.string.notice_room_aliases_added_and_removed, senderName, addedAliases.joinToString(), removedAliases.joinToString()) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_aliases_added_and_removed_by_you, addedAliases.joinToString(), removedAliases.joinToString()) + } else { + sp.getString(R.string.notice_room_aliases_added_and_removed, senderName, addedAliases.joinToString(), removedAliases.joinToString()) + } } else if (addedAliases.isNotEmpty()) { - sp.getQuantityString(R.plurals.notice_room_aliases_added, addedAliases.size, senderName, addedAliases.joinToString()) + if (event.isSentByCurrentUser()) { + sp.getQuantityString(R.plurals.notice_room_aliases_added_by_you, addedAliases.size, addedAliases.joinToString()) + } else { + sp.getQuantityString(R.plurals.notice_room_aliases_added, addedAliases.size, senderName, addedAliases.joinToString()) + } } else if (removedAliases.isNotEmpty()) { - sp.getQuantityString(R.plurals.notice_room_aliases_removed, removedAliases.size, senderName, removedAliases.joinToString()) + if (event.isSentByCurrentUser()) { + sp.getQuantityString(R.plurals.notice_room_aliases_removed_by_you, removedAliases.size, removedAliases.joinToString()) + } else { + sp.getQuantityString(R.plurals.notice_room_aliases_removed, removedAliases.size, senderName, removedAliases.joinToString()) + } } else { Timber.w("Alias event without any change...") null @@ -192,15 +252,33 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active val canonicalAlias = eventContent?.canonicalAlias return canonicalAlias ?.takeIf { it.isNotBlank() } - ?.let { sp.getString(R.string.notice_room_canonical_alias_set, senderName, it) } - ?: sp.getString(R.string.notice_room_canonical_alias_unset, senderName) + ?.let { + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_canonical_alias_set_by_you, it) + } else { + sp.getString(R.string.notice_room_canonical_alias_set, senderName, it) + } + } + ?: if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_canonical_alias_unset_by_you) + } else { + sp.getString(R.string.notice_room_canonical_alias_unset, senderName) + } } private fun formatRoomGuestAccessEvent(event: Event, senderName: String?): String? { val eventContent: RoomGuestAccessContent? = event.getClearContent().toModel() return when (eventContent?.guestAccess) { - GuestAccess.CanJoin -> sp.getString(R.string.notice_room_guest_access_can_join, senderName) - GuestAccess.Forbidden -> sp.getString(R.string.notice_room_guest_access_forbidden, senderName) + GuestAccess.CanJoin -> if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_guest_access_can_join_by_you) + } else { + sp.getString(R.string.notice_room_guest_access_can_join, senderName) + } + GuestAccess.Forbidden -> if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_guest_access_forbidden_by_you) + } else { + sp.getString(R.string.notice_room_guest_access_forbidden, senderName) + } else -> null } } @@ -208,9 +286,17 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active private fun formatRoomEncryptionEvent(event: Event, senderName: String?): CharSequence? { val content = event.content.toModel() ?: return null return if (content.algorithm == MXCRYPTO_ALGORITHM_MEGOLM) { - sp.getString(R.string.notice_end_to_end_ok, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_end_to_end_ok_by_you) + } else { + sp.getString(R.string.notice_end_to_end_ok, senderName) + } } else { - sp.getString(R.string.notice_end_to_end_unknown_algorithm, senderName, content.algorithm) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_end_to_end_unknown_algorithm_by_you, content.algorithm) + } else { + sp.getString(R.string.notice_end_to_end_unknown_algorithm, senderName, content.algorithm) + } } } @@ -220,11 +306,23 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active if (eventContent?.displayName != prevEventContent?.displayName) { val displayNameText = when { prevEventContent?.displayName.isNullOrEmpty() -> - sp.getString(R.string.notice_display_name_set, event.senderId, eventContent?.displayName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_display_name_set_by_you, eventContent?.displayName) + } else { + sp.getString(R.string.notice_display_name_set, event.senderId, eventContent?.displayName) + } eventContent?.displayName.isNullOrEmpty() -> - sp.getString(R.string.notice_display_name_removed, event.senderId, prevEventContent?.displayName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_display_name_removed_by_you, prevEventContent?.displayName) + } else { + sp.getString(R.string.notice_display_name_removed, event.senderId, prevEventContent?.displayName) + } else -> - sp.getString(R.string.notice_display_name_changed_from, event.senderId, prevEventContent?.displayName, eventContent?.displayName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_display_name_changed_from_by_you, prevEventContent?.displayName, eventContent?.displayName) + } else { + sp.getString(R.string.notice_display_name_changed_from, event.senderId, prevEventContent?.displayName, eventContent?.displayName) + } } displayText.append(displayNameText) } @@ -234,13 +332,21 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active displayText.append(" ") sp.getString(R.string.notice_avatar_changed_too) } else { - sp.getString(R.string.notice_avatar_url_changed, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_avatar_url_changed_by_you) + } else { + sp.getString(R.string.notice_avatar_url_changed, senderName) + } } displayText.append(displayAvatarText) } if (displayText.isEmpty()) { displayText.append( - sp.getString(R.string.notice_member_no_changes, senderName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_member_no_changes_by_you) + } else { + sp.getString(R.string.notice_member_no_changes, senderName) + } ) } return displayText.toString() @@ -257,62 +363,130 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active val userWhoHasAccepted = eventContent.thirdPartyInvite?.signed?.mxid ?: event.stateKey val threePidDisplayName = eventContent.thirdPartyInvite?.displayName ?: "" eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_third_party_registered_invite_with_reason, userWhoHasAccepted, threePidDisplayName, reason) - } ?: sp.getString(R.string.notice_room_third_party_registered_invite, userWhoHasAccepted, threePidDisplayName) + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_third_party_registered_invite_with_reason_by_you, threePidDisplayName, reason) + } else { + sp.getString(R.string.notice_room_third_party_registered_invite_with_reason, userWhoHasAccepted, threePidDisplayName, reason) + } + } ?: if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_third_party_registered_invite_by_you, threePidDisplayName) + } else { + sp.getString(R.string.notice_room_third_party_registered_invite, userWhoHasAccepted, threePidDisplayName) + } } event.stateKey == selfUserId -> eventContent.safeReason?.let { reason -> sp.getString(R.string.notice_room_invite_you_with_reason, senderDisplayName, reason) } ?: sp.getString(R.string.notice_room_invite_you, senderDisplayName) event.stateKey.isNullOrEmpty() -> - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_invite_no_invitee_with_reason, senderDisplayName, reason) - } ?: sp.getString(R.string.notice_room_invite_no_invitee, senderDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_invite_no_invitee_with_reason_by_you, reason) + } ?: sp.getString(R.string.notice_room_invite_no_invitee_by_you) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_invite_no_invitee_with_reason, senderDisplayName, reason) + } ?: sp.getString(R.string.notice_room_invite_no_invitee, senderDisplayName) + } else -> - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_invite_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_invite, senderDisplayName, targetDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_invite_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_invite_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_invite_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_invite, senderDisplayName, targetDisplayName) + } } } Membership.JOIN -> - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_join_with_reason, senderDisplayName, reason) - } ?: sp.getString(R.string.notice_room_join, senderDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_join_with_reason_by_you, reason) + } ?: sp.getString(R.string.notice_room_join_by_you) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_join_with_reason, senderDisplayName, reason) + } ?: sp.getString(R.string.notice_room_join, senderDisplayName) + } Membership.LEAVE -> // 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked if (event.senderId == event.stateKey) { if (prevEventContent?.membership == Membership.INVITE) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_reject_with_reason, senderDisplayName, reason) - } ?: sp.getString(R.string.notice_room_reject, senderDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_reject_with_reason_by_you, reason) + } ?: sp.getString(R.string.notice_room_reject_by_you) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_reject_with_reason, senderDisplayName, reason) + } ?: sp.getString(R.string.notice_room_reject, senderDisplayName) + } } else { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_leave_with_reason, senderDisplayName, reason) - } ?: sp.getString(R.string.notice_room_leave, senderDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_leave_with_reason_by_you, reason) + } ?: sp.getString(R.string.notice_room_leave_by_you) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_leave_with_reason, senderDisplayName, reason) + } ?: sp.getString(R.string.notice_room_leave, senderDisplayName) + } } } else if (prevEventContent?.membership == Membership.INVITE) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_withdraw_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_withdraw, senderDisplayName, targetDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_withdraw_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_withdraw_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_withdraw_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_withdraw, senderDisplayName, targetDisplayName) + } } else if (prevEventContent?.membership == Membership.JOIN) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_kick_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_kick_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_kick_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_kick_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName) + } } else if (prevEventContent?.membership == Membership.BAN) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_unban_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_unban, senderDisplayName, targetDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_unban_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_unban_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_unban_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_unban, senderDisplayName, targetDisplayName) + } } else { null } Membership.BAN -> - eventContent.safeReason?.let { - sp.getString(R.string.notice_room_ban_with_reason, senderDisplayName, targetDisplayName, it) - } ?: sp.getString(R.string.notice_room_ban, senderDisplayName, targetDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { + sp.getString(R.string.notice_room_ban_with_reason_by_you, targetDisplayName, it) + } ?: sp.getString(R.string.notice_room_ban_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { + sp.getString(R.string.notice_room_ban_with_reason, senderDisplayName, targetDisplayName, it) + } ?: sp.getString(R.string.notice_room_ban, senderDisplayName, targetDisplayName) + } Membership.KNOCK -> - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_kick_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName) + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_kick_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_kick_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_kick_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName) + } else -> null } } @@ -320,8 +494,16 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active private fun formatJoinRulesEvent(event: Event, senderName: String?): CharSequence? { val content = event.getClearContent().toModel() ?: return null return when (content.joinRules) { - RoomJoinRules.INVITE -> sp.getString(R.string.room_join_rules_invite, senderName) - RoomJoinRules.PUBLIC -> sp.getString(R.string.room_join_rules_public, senderName) + RoomJoinRules.INVITE -> if (event.isSentByCurrentUser()) { + sp.getString(R.string.room_join_rules_invite_by_you) + } else { + sp.getString(R.string.room_join_rules_invite, senderName) + } + RoomJoinRules.PUBLIC -> if (event.isSentByCurrentUser()) { + sp.getString(R.string.room_join_rules_public_by_you) + } else { + sp.getString(R.string.room_join_rules_public, senderName) + } else -> null } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt index 3985b3856b..cf044f8a37 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt @@ -46,8 +46,12 @@ abstract class MergedRoomCreationItem : BasedMergedItem Unit, - val hasEncryptionEvent : Boolean, + val currentUserId: String, + val hasEncryptionEvent: Boolean, val isEncryptionAlgorithmSecure: Boolean ) : BasedMergedItem.Attributes } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 36521e897e..60b74570ba 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1823,6 +1823,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming "Settings" "Leave the room" "%1$s made no changes" + "You made no changes" Sends the given message as a spoiler Spoiler Type keywords to find a reaction. @@ -1833,7 +1834,9 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming %1$s made the room public to whoever knows the link. + You made the room public to whoever knows the link. %1$s made the room invite only. + You made the room invite only. Unread messages Liberate your communication @@ -2302,6 +2305,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming The encryption used by this room is not supported %s created and configured the room. + You created and configured the room. Almost there! Is the other device showing the same shield? Almost there! Waiting for confirmation… From a39d35e54c15f827e215bc7a37ada6b589bcc201 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 27 May 2020 22:23:49 +0200 Subject: [PATCH 2/3] Improve Kotlin code readability: use `when` instead of `if` and add a few newlines --- .../timeline/format/NoticeEventFormatter.kt | 238 +++++++++--------- 1 file changed, 125 insertions(+), 113 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt index 5d6f65317d..eff5444a91 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/format/NoticeEventFormatter.kt @@ -191,16 +191,18 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active } } } - EventType.CALL_ANSWER -> if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_answered_call_by_you) - } else { - sp.getString(R.string.notice_answered_call, senderName) - } - EventType.CALL_HANGUP -> if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_ended_call_by_you) - } else { - sp.getString(R.string.notice_ended_call, senderName) - } + EventType.CALL_ANSWER -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_answered_call_by_you) + } else { + sp.getString(R.string.notice_answered_call, senderName) + } + EventType.CALL_HANGUP -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_ended_call_by_you) + } else { + sp.getString(R.string.notice_ended_call, senderName) + } else -> null } } @@ -223,27 +225,29 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active val addedAliases = eventContent?.aliases.orEmpty() - prevEventContent?.aliases.orEmpty() val removedAliases = prevEventContent?.aliases.orEmpty() - eventContent?.aliases.orEmpty() - return if (addedAliases.isNotEmpty() && removedAliases.isNotEmpty()) { - if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_room_aliases_added_and_removed_by_you, addedAliases.joinToString(), removedAliases.joinToString()) - } else { - sp.getString(R.string.notice_room_aliases_added_and_removed, senderName, addedAliases.joinToString(), removedAliases.joinToString()) + return when { + addedAliases.isNotEmpty() && removedAliases.isNotEmpty() -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_aliases_added_and_removed_by_you, addedAliases.joinToString(), removedAliases.joinToString()) + } else { + sp.getString(R.string.notice_room_aliases_added_and_removed, senderName, addedAliases.joinToString(), removedAliases.joinToString()) + } + addedAliases.isNotEmpty() -> + if (event.isSentByCurrentUser()) { + sp.getQuantityString(R.plurals.notice_room_aliases_added_by_you, addedAliases.size, addedAliases.joinToString()) + } else { + sp.getQuantityString(R.plurals.notice_room_aliases_added, addedAliases.size, senderName, addedAliases.joinToString()) + } + removedAliases.isNotEmpty() -> + if (event.isSentByCurrentUser()) { + sp.getQuantityString(R.plurals.notice_room_aliases_removed_by_you, removedAliases.size, removedAliases.joinToString()) + } else { + sp.getQuantityString(R.plurals.notice_room_aliases_removed, removedAliases.size, senderName, removedAliases.joinToString()) + } + else -> { + Timber.w("Alias event without any change...") + null } - } else if (addedAliases.isNotEmpty()) { - if (event.isSentByCurrentUser()) { - sp.getQuantityString(R.plurals.notice_room_aliases_added_by_you, addedAliases.size, addedAliases.joinToString()) - } else { - sp.getQuantityString(R.plurals.notice_room_aliases_added, addedAliases.size, senderName, addedAliases.joinToString()) - } - } else if (removedAliases.isNotEmpty()) { - if (event.isSentByCurrentUser()) { - sp.getQuantityString(R.plurals.notice_room_aliases_removed_by_you, removedAliases.size, removedAliases.joinToString()) - } else { - sp.getQuantityString(R.plurals.notice_room_aliases_removed, removedAliases.size, senderName, removedAliases.joinToString()) - } - } else { - Timber.w("Alias event without any change...") - null } } @@ -269,34 +273,37 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active private fun formatRoomGuestAccessEvent(event: Event, senderName: String?): String? { val eventContent: RoomGuestAccessContent? = event.getClearContent().toModel() return when (eventContent?.guestAccess) { - GuestAccess.CanJoin -> if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_room_guest_access_can_join_by_you) - } else { - sp.getString(R.string.notice_room_guest_access_can_join, senderName) - } - GuestAccess.Forbidden -> if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_room_guest_access_forbidden_by_you) - } else { - sp.getString(R.string.notice_room_guest_access_forbidden, senderName) - } + GuestAccess.CanJoin -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_guest_access_can_join_by_you) + } else { + sp.getString(R.string.notice_room_guest_access_can_join, senderName) + } + GuestAccess.Forbidden -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_room_guest_access_forbidden_by_you) + } else { + sp.getString(R.string.notice_room_guest_access_forbidden, senderName) + } else -> null } } private fun formatRoomEncryptionEvent(event: Event, senderName: String?): CharSequence? { val content = event.content.toModel() ?: return null - return if (content.algorithm == MXCRYPTO_ALGORITHM_MEGOLM) { - if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_end_to_end_ok_by_you) - } else { - sp.getString(R.string.notice_end_to_end_ok, senderName) - } - } else { - if (event.isSentByCurrentUser()) { - sp.getString(R.string.notice_end_to_end_unknown_algorithm_by_you, content.algorithm) - } else { - sp.getString(R.string.notice_end_to_end_unknown_algorithm, senderName, content.algorithm) - } + return when (content.algorithm) { + MXCRYPTO_ALGORITHM_MEGOLM -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_end_to_end_ok_by_you) + } else { + sp.getString(R.string.notice_end_to_end_ok, senderName) + } + else -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.notice_end_to_end_unknown_algorithm_by_you, content.algorithm) + } else { + sp.getString(R.string.notice_end_to_end_unknown_algorithm, senderName, content.algorithm) + } } } @@ -413,59 +420,62 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active Membership.LEAVE -> // 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked if (event.senderId == event.stateKey) { - if (prevEventContent?.membership == Membership.INVITE) { - if (event.isSentByCurrentUser()) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_reject_with_reason_by_you, reason) - } ?: sp.getString(R.string.notice_room_reject_by_you) - } else { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_reject_with_reason, senderDisplayName, reason) - } ?: sp.getString(R.string.notice_room_reject, senderDisplayName) - } - } else { - if (event.isSentByCurrentUser()) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_leave_with_reason_by_you, reason) - } ?: sp.getString(R.string.notice_room_leave_by_you) - } else { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_leave_with_reason, senderDisplayName, reason) - } ?: sp.getString(R.string.notice_room_leave, senderDisplayName) - } - } - } else if (prevEventContent?.membership == Membership.INVITE) { - if (event.isSentByCurrentUser()) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_withdraw_with_reason_by_you, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_withdraw_by_you, targetDisplayName) - } else { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_withdraw_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_withdraw, senderDisplayName, targetDisplayName) - } - } else if (prevEventContent?.membership == Membership.JOIN) { - if (event.isSentByCurrentUser()) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_kick_with_reason_by_you, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_kick_by_you, targetDisplayName) - } else { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_kick_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName) - } - } else if (prevEventContent?.membership == Membership.BAN) { - if (event.isSentByCurrentUser()) { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_unban_with_reason_by_you, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_unban_by_you, targetDisplayName) - } else { - eventContent.safeReason?.let { reason -> - sp.getString(R.string.notice_room_unban_with_reason, senderDisplayName, targetDisplayName, reason) - } ?: sp.getString(R.string.notice_room_unban, senderDisplayName, targetDisplayName) + when (prevEventContent?.membership) { + Membership.INVITE -> + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_reject_with_reason_by_you, reason) + } ?: sp.getString(R.string.notice_room_reject_by_you) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_reject_with_reason, senderDisplayName, reason) + } ?: sp.getString(R.string.notice_room_reject, senderDisplayName) + } + else -> + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_leave_with_reason_by_you, reason) + } ?: sp.getString(R.string.notice_room_leave_by_you) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_leave_with_reason, senderDisplayName, reason) + } ?: sp.getString(R.string.notice_room_leave, senderDisplayName) + } } } else { - null + when (prevEventContent?.membership) { + Membership.INVITE -> + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_withdraw_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_withdraw_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_withdraw_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_withdraw, senderDisplayName, targetDisplayName) + } + Membership.JOIN -> + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_kick_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_kick_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_kick_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_kick, senderDisplayName, targetDisplayName) + } + Membership.BAN -> + if (event.isSentByCurrentUser()) { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_unban_with_reason_by_you, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_unban_by_you, targetDisplayName) + } else { + eventContent.safeReason?.let { reason -> + sp.getString(R.string.notice_room_unban_with_reason, senderDisplayName, targetDisplayName, reason) + } ?: sp.getString(R.string.notice_room_unban, senderDisplayName, targetDisplayName) + } + else -> null + } } Membership.BAN -> if (event.isSentByCurrentUser()) { @@ -494,16 +504,18 @@ class NoticeEventFormatter @Inject constructor(private val sessionHolder: Active private fun formatJoinRulesEvent(event: Event, senderName: String?): CharSequence? { val content = event.getClearContent().toModel() ?: return null return when (content.joinRules) { - RoomJoinRules.INVITE -> if (event.isSentByCurrentUser()) { - sp.getString(R.string.room_join_rules_invite_by_you) - } else { - sp.getString(R.string.room_join_rules_invite, senderName) - } - RoomJoinRules.PUBLIC -> if (event.isSentByCurrentUser()) { - sp.getString(R.string.room_join_rules_public_by_you) - } else { - sp.getString(R.string.room_join_rules_public, senderName) - } + RoomJoinRules.INVITE -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.room_join_rules_invite_by_you) + } else { + sp.getString(R.string.room_join_rules_invite, senderName) + } + RoomJoinRules.PUBLIC -> + if (event.isSentByCurrentUser()) { + sp.getString(R.string.room_join_rules_public_by_you) + } else { + sp.getString(R.string.room_join_rules_public, senderName) + } else -> null } } From ca855da8ae41fe69df023d7ad32af1dfcfaec2c8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Jun 2020 13:12:51 +0200 Subject: [PATCH 3/3] Fix issue reported during review by Onuray --- matrix-sdk-android/src/main/res/values/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index b407ca8eba..1010d5fe48 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -32,7 +32,7 @@ %1$s set their display name to %2$s You set your display name to %1$s %1$s changed their display name from %2$s to %3$s - You changed their display name from %1$s to %2$s + You changed your display name from %1$s to %2$s %1$s removed their display name (%2$s) You removed your display name (%1$s) %1$s changed the topic to: %2$s @@ -74,7 +74,7 @@ Message removed [reason: %1$s] Message removed by %1$s [reason: %2$s] %1$s updated their profile %2$s - You updated your profile %2$s + You updated your profile %1$s %1$s sent an invitation to %2$s to join the room You sent an invitation to %1$s to join the room %1$s revoked the invitation for %2$s to join the room @@ -277,7 +277,7 @@ Clear sending queue %1$s\'s invitation. Reason: %2$s - Your invitation. Reason: %2$s + Your invitation. Reason: %1$s %1$s invited %2$s. Reason: %3$s You invited %1$s. Reason: %2$s %1$s invited you. Reason: %2$s