diff --git a/CHANGES.md b/CHANGES.md
index fd076e27ea..9348717fb5 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,6 +5,7 @@ Features ✨:
-
Improvements 🙌:
+ - Wording differentiation for direct rooms (#2176)
- PIN code: request PIN code if phone has been locked
- Small optimisation of scrolling experience in timeline (#2114)
diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml
index f64ec9926e..3f75b715f6 100644
--- a/matrix-sdk-android/src/main/res/values/strings.xml
+++ b/matrix-sdk-android/src/main/res/values/strings.xml
@@ -10,13 +10,19 @@
Your invitation
%1$s created the room
You created the room
+ %1$s created the discussion
+ You created the discussion
%1$s invited %2$s
You invited %1$s
%1$s invited you
%1$s joined the room
You joined the room
+ %1$s joined
+ You joined
%1$s left the room
You left 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
@@ -53,6 +59,8 @@
You ended the call.
%1$s made future room history visible to %2$s
You made future room history visible to %1$s
+ %1$s made future messages visible to %2$s
+ You made future messages visible to %1$s
all room members, from the point they are invited.
all room members, from the point they joined.
all room members.
@@ -62,6 +70,8 @@
You turned on end-to-end encryption (%1$s)
%s upgraded this room.
You upgraded this room.
+ %s upgraded here.
+ You upgraded here.
%1$s requested a VoIP conference
You requested a VoIP conference
@@ -83,8 +93,12 @@
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 invited %2$s
+ You invited %1$s
%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 revoked the invitation for %2$s
+ You revoked the invitation for %1$s
%1$s accepted the invitation for %2$s
You accepted the invitation for %1$s
@@ -171,8 +185,12 @@
%1$s invited you. Reason: %2$s
%1$s joined the room. Reason: %2$s
You joined the room. Reason: %1$s
+ %1$s joined. Reason: %2$s
+ You joined. Reason: %1$s
%1$s left the room. Reason: %2$s
You left the room. Reason: %1$s
+ %1$s left. Reason: %2$s
+ You left. 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
@@ -220,8 +238,12 @@
"%1$s has allowed guests to join the room."
"You have allowed guests to join the room."
+ "%1$s has allowed guests to join here."
+ "You have allowed guests to join here."
"%1$s has prevented guests from joining the room."
"You have prevented guests from joining 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.
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
index e7140f06f4..3b4795b965 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
@@ -704,7 +704,13 @@ class RoomDetailFragment @Inject constructor(
// safeStartCall(it, isVideoCall)
// }
} else if (!state.isAllowedToStartWebRTCCall) {
- showDialogWithMessage(getString(R.string.no_permissions_to_start_webrtc_call))
+ showDialogWithMessage(getString(
+ if (state.isDm()) {
+ R.string.no_permissions_to_start_webrtc_call_in_direct_room
+ } else {
+ R.string.no_permissions_to_start_webrtc_call
+ })
+ )
} else {
safeStartCall(isVideoCall)
}
@@ -714,7 +720,13 @@ class RoomDetailFragment @Inject constructor(
// can you add widgets??
if (!state.isAllowedToManageWidgets) {
// You do not have permission to start a conference call in this room
- showDialogWithMessage(getString(R.string.no_permissions_to_start_conf_call))
+ showDialogWithMessage(getString(
+ if (state.isDm()) {
+ R.string.no_permissions_to_start_conf_call_in_direct_room
+ } else {
+ R.string.no_permissions_to_start_conf_call
+ }
+ ))
} else {
if (state.activeRoomWidgets()?.filter { it.type == WidgetType.Jitsi }?.any() == true) {
// A conference is already in progress!
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt
index 16a7379b6a..36acc35148 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt
@@ -77,4 +77,6 @@ data class RoomDetailViewState(
// Also highlight the target event, if any
highlightedEventId = args.eventId
)
+
+ fun isDm() = asyncRoomSummary()?.isDirect == true
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
index a49b74c243..8a25e5fc93 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
@@ -190,7 +190,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
EventType.CALL_CANDIDATES,
EventType.CALL_HANGUP,
EventType.CALL_ANSWER -> {
- noticeEventFormatter.format(timelineEvent)
+ noticeEventFormatter.format(timelineEvent, room?.roomSummary())
}
else -> null
} ?: ""
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt
index 5374b4792a..4f2c8ea63a 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt
@@ -25,6 +25,8 @@ import im.vector.app.features.home.room.detail.timeline.helper.MessageInformatio
import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory
import im.vector.app.features.home.room.detail.timeline.item.StatusTileTimelineItem
import im.vector.app.features.home.room.detail.timeline.item.StatusTileTimelineItem_
+import org.matrix.android.sdk.api.extensions.orFalse
+import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
@@ -36,7 +38,8 @@ class EncryptionItemFactory @Inject constructor(
private val messageColorProvider: MessageColorProvider,
private val stringProvider: StringProvider,
private val informationDataFactory: MessageInformationDataFactory,
- private val avatarSizeProvider: AvatarSizeProvider) {
+ private val avatarSizeProvider: AvatarSizeProvider,
+ private val session: Session) {
fun create(event: TimelineEvent,
highlight: Boolean,
@@ -51,7 +54,13 @@ class EncryptionItemFactory @Inject constructor(
val shield: StatusTileTimelineItem.ShieldUIState
if (isSafeAlgorithm) {
title = stringProvider.getString(R.string.encryption_enabled)
- description = stringProvider.getString(R.string.encryption_enabled_tile_description)
+ description = stringProvider.getString(
+ if (session.getRoomSummary(event.root.roomId ?: "")?.isDirect.orFalse()) {
+ R.string.direct_room_encryption_enabled_tile_description
+ } else {
+ R.string.encryption_enabled_tile_description
+ }
+ )
shield = StatusTileTimelineItem.ShieldUIState.BLACK
} else {
title = stringProvider.getString(R.string.encryption_not_enabled)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt
index 0ba3b4d47e..08f93b23cd 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MergedHeaderItemFactory.kt
@@ -22,6 +22,7 @@ import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
import im.vector.app.features.home.room.detail.timeline.helper.MergedTimelineEventVisibilityStateChangedListener
+import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder
import im.vector.app.features.home.room.detail.timeline.helper.canBeMerged
import im.vector.app.features.home.room.detail.timeline.helper.isRoomConfiguration
import im.vector.app.features.home.room.detail.timeline.helper.prevSameTypeEvents
@@ -33,6 +34,7 @@ import im.vector.app.features.home.room.detail.timeline.item.MergedRoomCreationI
import im.vector.app.features.home.room.detail.timeline.item.MergedUTDItem
import im.vector.app.features.home.room.detail.timeline.item.MergedUTDItem_
import im.vector.app.features.settings.VectorPreferences
+import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
@@ -45,6 +47,7 @@ import javax.inject.Inject
class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
private val avatarRenderer: AvatarRenderer,
private val avatarSizeProvider: AvatarSizeProvider,
+ private val roomSummaryHolder: RoomSummaryHolder,
private val vectorPreferences: VectorPreferences) {
private val collapsedEventIds = linkedSetOf()
@@ -78,6 +81,8 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
}
}
+ private fun isDirectRoom() = roomSummaryHolder.roomSummary?.isDirect.orFalse()
+
private fun buildMembershipEventsMergedSummary(currentPosition: Int,
items: List,
event: TimelineEvent,
@@ -100,7 +105,8 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
avatarUrl = mergedEvent.senderInfo.avatarUrl,
memberName = mergedEvent.senderInfo.disambiguatedDisplayName,
localId = mergedEvent.localId,
- eventId = mergedEvent.root.eventId ?: ""
+ eventId = mergedEvent.root.eventId ?: "",
+ isDirectRoom = isDirectRoom()
)
mergedData.add(data)
}
@@ -157,7 +163,7 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
items: List,
event: TimelineEvent,
eventIdToHighlight: String?,
- // requestModelBuild: () -> Unit,
+ // requestModelBuild: () -> Unit,
callback: TimelineEventController.Callback?): MergedUTDItem_? {
Timber.v("## MERGE: buildUTDMergedSummary from position $currentPosition")
var prevEvent = items.prevOrNull(currentPosition)
@@ -187,7 +193,8 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
avatarUrl = senderAvatar,
memberName = senderName,
localId = mergedEvent.localId,
- eventId = mergedEvent.root.eventId ?: ""
+ eventId = mergedEvent.root.eventId ?: "",
+ isDirectRoom = isDirectRoom()
)
mergedData.add(data)
}
@@ -247,7 +254,8 @@ class MergedHeaderItemFactory @Inject constructor(private val activeSessionHolde
avatarUrl = mergedEvent.senderInfo.avatarUrl,
memberName = mergedEvent.senderInfo.disambiguatedDisplayName,
localId = mergedEvent.localId,
- eventId = mergedEvent.root.eventId ?: ""
+ eventId = mergedEvent.root.eventId ?: "",
+ isDirectRoom = isDirectRoom()
)
mergedData.add(data)
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
index 97bc693f26..1e809d9ab5 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
@@ -38,6 +38,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.ContentDownloadSt
import im.vector.app.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory
+import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder
import im.vector.app.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem
import im.vector.app.features.home.room.detail.timeline.item.MessageBlockCodeItem
@@ -101,6 +102,7 @@ class MessageItemFactory @Inject constructor(
private val messageItemAttributesFactory: MessageItemAttributesFactory,
private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder,
private val contentDownloadStateTrackerBinder: ContentDownloadStateTrackerBinder,
+ private val roomSummaryHolder: RoomSummaryHolder,
private val defaultItemFactory: DefaultItemFactory,
private val noticeItemFactory: NoticeItemFactory,
private val avatarSizeProvider: AvatarSizeProvider,
@@ -130,7 +132,7 @@ class MessageItemFactory @Inject constructor(
|| event.isEncrypted() && event.root.content.toModel()?.relatesTo?.type == RelationType.REPLACE
) {
// This is an edit event, we should display it when debugging as a notice event
- return noticeItemFactory.create(event, highlight, callback)
+ return noticeItemFactory.create(event, highlight, roomSummaryHolder.roomSummary, callback)
}
val attributes = messageItemAttributesFactory.create(messageContent, informationData, callback)
@@ -146,7 +148,7 @@ class MessageItemFactory @Inject constructor(
is MessageAudioContent -> buildAudioMessageItem(messageContent, informationData, highlight, attributes)
is MessageVerificationRequestContent -> buildVerificationRequestMessageItem(messageContent, informationData, highlight, callback, attributes)
is MessageOptionsContent -> buildOptionsMessageItem(messageContent, informationData, highlight, callback, attributes)
- is MessagePollResponseContent -> noticeItemFactory.create(event, highlight, callback)
+ is MessagePollResponseContent -> noticeItemFactory.create(event, highlight, roomSummaryHolder.roomSummary, callback)
else -> buildNotHandledMessageItem(messageContent, informationData, highlight, callback, attributes)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/NoticeItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/NoticeItemFactory.kt
index cd8c682f39..ec065543f5 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/NoticeItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/NoticeItemFactory.kt
@@ -24,6 +24,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvide
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
import im.vector.app.features.home.room.detail.timeline.item.NoticeItem
import im.vector.app.features.home.room.detail.timeline.item.NoticeItem_
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import javax.inject.Inject
@@ -34,8 +35,9 @@ class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEv
fun create(event: TimelineEvent,
highlight: Boolean,
+ roomSummary: RoomSummary?,
callback: TimelineEventController.Callback?): NoticeItem? {
- val formattedText = eventFormatter.format(event) ?: return null
+ val formattedText = eventFormatter.format(event, roomSummary) ?: return null
val informationData = informationDataFactory.create(event, null)
val attributes = NoticeItem.Attributes(
avatarRenderer = avatarRenderer,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/RoomCreateItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/RoomCreateItemFactory.kt
index 31adbdb8a6..25b5fd718b 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/RoomCreateItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/RoomCreateItemFactory.kt
@@ -21,6 +21,7 @@ import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
+import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder
import im.vector.app.features.home.room.detail.timeline.item.RoomCreateItem_
import me.gujun.android.span.span
import org.matrix.android.sdk.api.session.Session
@@ -32,6 +33,7 @@ import javax.inject.Inject
class RoomCreateItemFactory @Inject constructor(private val stringProvider: StringProvider,
private val userPreferencesProvider: UserPreferencesProvider,
private val session: Session,
+ private val roomSummaryHolder: RoomSummaryHolder,
private val noticeItemFactory: NoticeItemFactory) {
fun create(event: TimelineEvent, callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {
@@ -52,7 +54,7 @@ class RoomCreateItemFactory @Inject constructor(private val stringProvider: Stri
private fun defaultRendering(event: TimelineEvent, callback: TimelineEventController.Callback?): VectorEpoxyModel<*>? {
return if (userPreferencesProvider.shouldShowHiddenEvents()) {
- noticeItemFactory.create(event, false, callback)
+ noticeItemFactory.create(event, false, roomSummaryHolder.roomSummary, callback)
} else {
null
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt
index 1f99efd08e..40286678c8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt
@@ -20,6 +20,7 @@ import im.vector.app.core.epoxy.EmptyItem_
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.resources.UserPreferencesProvider
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
+import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import timber.log.Timber
@@ -31,6 +32,7 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
private val defaultItemFactory: DefaultItemFactory,
private val encryptionItemFactory: EncryptionItemFactory,
private val roomCreateItemFactory: RoomCreateItemFactory,
+ private val roomSummaryHolder: RoomSummaryHolder,
private val verificationConclusionItemFactory: VerificationItemFactory,
private val userPreferencesProvider: UserPreferencesProvider) {
@@ -63,10 +65,8 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
EventType.CALL_ANSWER,
EventType.STATE_ROOM_POWER_LEVELS,
EventType.REACTION,
- EventType.REDACTION -> noticeItemFactory.create(event, highlight, callback)
- EventType.STATE_ROOM_ENCRYPTION -> {
- encryptionItemFactory.create(event, highlight, callback)
- }
+ EventType.REDACTION -> noticeItemFactory.create(event, highlight, roomSummaryHolder.roomSummary, callback)
+ EventType.STATE_ROOM_ENCRYPTION -> encryptionItemFactory.create(event, highlight, callback)
// State room create
EventType.STATE_ROOM_CREATE -> roomCreateItemFactory.create(event, callback)
// Crypto
@@ -87,7 +87,7 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me
// TODO These are not filtered out by timeline when encrypted
// For now manually ignore
if (userPreferencesProvider.shouldShowHiddenEvents()) {
- noticeItemFactory.create(event, highlight, callback)
+ noticeItemFactory.create(event, highlight, roomSummaryHolder.roomSummary, callback)
} else {
null
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt
index 0b623d78f1..59daf5a0a0 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt
@@ -24,6 +24,7 @@ import im.vector.app.features.home.room.detail.timeline.TimelineEventController
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory
+import im.vector.app.features.home.room.detail.timeline.helper.RoomSummaryHolder
import im.vector.app.features.home.room.detail.timeline.item.StatusTileTimelineItem
import im.vector.app.features.home.room.detail.timeline.item.StatusTileTimelineItem_
import org.matrix.android.sdk.api.session.Session
@@ -50,6 +51,7 @@ class VerificationItemFactory @Inject constructor(
private val avatarSizeProvider: AvatarSizeProvider,
private val noticeItemFactory: NoticeItemFactory,
private val userPreferencesProvider: UserPreferencesProvider,
+ private val roomSummaryHolder: RoomSummaryHolder,
private val stringProvider: StringProvider,
private val session: Session
) {
@@ -151,7 +153,7 @@ class VerificationItemFactory @Inject constructor(
highlight: Boolean,
callback: TimelineEventController.Callback?
): VectorEpoxyModel<*>? {
- if (userPreferencesProvider.shouldShowHiddenEvents()) return noticeItemFactory.create(event, highlight, callback)
+ if (userPreferencesProvider.shouldShowHiddenEvents()) return noticeItemFactory.create(event, highlight, roomSummaryHolder.roomSummary, callback)
return null
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt
index cb9f583a2a..78d9a49c9c 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt
@@ -23,6 +23,7 @@ import im.vector.app.core.resources.StringProvider
import me.gujun.android.span.span
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageOptionsContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType
import org.matrix.android.sdk.api.session.room.model.message.OPTION_TYPE_BUTTONS
@@ -40,7 +41,7 @@ class DisplayableEventFormatter @Inject constructor(
private val noticeEventFormatter: NoticeEventFormatter
) {
- fun format(timelineEvent: TimelineEvent, appendAuthor: Boolean): CharSequence {
+ fun format(timelineEvent: TimelineEvent, appendAuthor: Boolean, roomSummary: RoomSummary?): CharSequence {
if (timelineEvent.root.isRedacted()) {
return noticeEventFormatter.formatRedactedEvent(timelineEvent.root)
}
@@ -130,7 +131,7 @@ class DisplayableEventFormatter @Inject constructor(
}
else -> {
return span {
- text = noticeEventFormatter.format(timelineEvent) ?: ""
+ text = noticeEventFormatter.format(timelineEvent, roomSummary) ?: ""
textStyle = "italic"
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt
index 9a4729abee..e26472feb0 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/NoticeEventFormatter.kt
@@ -35,6 +35,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomNameContent
+import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
@@ -56,23 +57,26 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
private fun Event.isSentByCurrentUser() = senderId != null && senderId == currentUserId
- fun format(timelineEvent: TimelineEvent): CharSequence? {
+ private fun RoomSummary?.isDm() = this?.isDirect.orFalse()
+
+ fun format(timelineEvent: TimelineEvent, rs: RoomSummary?): CharSequence? {
return when (val type = timelineEvent.root.getClearType()) {
- EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
- EventType.STATE_ROOM_CREATE -> formatRoomCreateEvent(timelineEvent.root)
+ EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs)
+ EventType.STATE_ROOM_CREATE -> formatRoomCreateEvent(timelineEvent.root, rs)
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_AVATAR -> formatRoomAvatarEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
- EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
- EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
+ EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs)
+ EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs)
EventType.STATE_ROOM_ALIASES -> formatRoomAliasesEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_CANONICAL_ALIAS -> formatRoomCanonicalAliasEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
- 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_HISTORY_VISIBILITY ->
+ formatRoomHistoryVisibilityEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs)
+ EventType.STATE_ROOM_GUEST_ACCESS -> formatRoomGuestAccessEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs)
EventType.STATE_ROOM_ENCRYPTION -> formatRoomEncryptionEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.STATE_ROOM_WIDGET,
EventType.STATE_ROOM_WIDGET_LEGACY -> formatWidgetEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
- EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
+ EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName, rs)
EventType.STATE_ROOM_POWER_LEVELS -> formatRoomPowerLevels(timelineEvent.root, timelineEvent.senderInfo.disambiguatedDisplayName)
EventType.CALL_INVITE,
EventType.CALL_CANDIDATES,
@@ -151,19 +155,19 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
- fun format(event: Event, senderName: String?): CharSequence? {
+ fun format(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? {
return when (val type = event.getClearType()) {
- EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(event, senderName)
+ EventType.STATE_ROOM_JOIN_RULES -> formatJoinRulesEvent(event, senderName, rs)
EventType.STATE_ROOM_NAME -> formatRoomNameEvent(event, senderName)
EventType.STATE_ROOM_TOPIC -> formatRoomTopicEvent(event, senderName)
EventType.STATE_ROOM_AVATAR -> formatRoomAvatarEvent(event, senderName)
- EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName)
- EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(event, senderName)
- EventType.STATE_ROOM_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(event, senderName)
+ EventType.STATE_ROOM_MEMBER -> formatRoomMemberEvent(event, senderName, rs)
+ EventType.STATE_ROOM_THIRD_PARTY_INVITE -> formatRoomThirdPartyInvite(event, senderName, rs)
+ EventType.STATE_ROOM_HISTORY_VISIBILITY -> formatRoomHistoryVisibilityEvent(event, senderName, rs)
EventType.CALL_INVITE,
EventType.CALL_HANGUP,
EventType.CALL_ANSWER -> formatCallEvent(type, event, senderName)
- EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(event, senderName)
+ EventType.STATE_ROOM_TOMBSTONE -> formatRoomTombstoneEvent(event, senderName, rs)
else -> {
Timber.v("Type $type not handled by this formatter")
null
@@ -175,14 +179,14 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
return "{ \"type\": ${event.getClearType()} }"
}
- private fun formatRoomCreateEvent(event: Event): CharSequence? {
+ private fun formatRoomCreateEvent(event: Event, rs: RoomSummary?): CharSequence? {
return event.getClearContent().toModel()
?.takeIf { it.creator.isNullOrBlank().not() }
?.let {
if (event.isSentByCurrentUser()) {
- sp.getString(R.string.notice_room_created_by_you)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_created_by_you else R.string.notice_room_created_by_you)
} else {
- sp.getString(R.string.notice_room_created, it.creator)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_created else R.string.notice_room_created, it.creator)
}
}
}
@@ -204,11 +208,11 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
- private fun formatRoomTombstoneEvent(event: Event, senderName: String?): CharSequence? {
+ private fun formatRoomTombstoneEvent(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? {
return if (event.isSentByCurrentUser()) {
- sp.getString(R.string.notice_room_update_by_you)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_update_by_you else R.string.notice_room_update_by_you)
} else {
- sp.getString(R.string.notice_room_update, senderName)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_update else R.string.notice_room_update, senderName)
}
}
@@ -246,18 +250,20 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
- private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?): CharSequence? {
+ private fun formatRoomHistoryVisibilityEvent(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? {
val historyVisibility = event.getClearContent().toModel()?.historyVisibility ?: return null
val formattedVisibility = roomHistoryVisibilityFormatter.format(historyVisibility)
return if (event.isSentByCurrentUser()) {
- sp.getString(R.string.notice_made_future_room_visibility_by_you, formattedVisibility)
+ sp.getString(if (rs.isDm()) R.string.notice_made_future_direct_room_visibility_by_you else R.string.notice_made_future_room_visibility_by_you,
+ formattedVisibility)
} else {
- sp.getString(R.string.notice_made_future_room_visibility, senderName, formattedVisibility)
+ sp.getString(if (rs.isDm()) R.string.notice_made_future_direct_room_visibility else R.string.notice_made_future_room_visibility,
+ senderName, formattedVisibility)
}
}
- private fun formatRoomThirdPartyInvite(event: Event, senderName: String?): CharSequence? {
+ private fun formatRoomThirdPartyInvite(event: Event, senderName: String?, rs: RoomSummary?): CharSequence? {
val content = event.getClearContent().toModel()
val prevContent = event.resolvedPrevContent()?.toModel()
@@ -265,17 +271,26 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
prevContent != null -> {
// Revoke case
if (event.isSentByCurrentUser()) {
- sp.getString(R.string.notice_room_third_party_revoked_invite_by_you, prevContent.displayName)
+ sp.getString(
+ if (rs.isDm()) {
+ R.string.notice_direct_room_third_party_revoked_invite_by_you
+ } else {
+ R.string.notice_room_third_party_revoked_invite_by_you
+ },
+ prevContent.displayName)
} else {
- sp.getString(R.string.notice_room_third_party_revoked_invite, senderName, prevContent.displayName)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_third_party_revoked_invite else R.string.notice_room_third_party_revoked_invite,
+ senderName, prevContent.displayName)
}
}
content != null -> {
// Invitation case
if (event.isSentByCurrentUser()) {
- sp.getString(R.string.notice_room_third_party_invite_by_you, content.displayName)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_third_party_invite_by_you else R.string.notice_room_third_party_invite_by_you,
+ content.displayName)
} else {
- sp.getString(R.string.notice_room_third_party_invite, senderName, content.displayName)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_third_party_invite else R.string.notice_room_third_party_invite,
+ senderName, content.displayName)
}
}
else -> null
@@ -323,13 +338,13 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
- private fun formatRoomMemberEvent(event: Event, senderName: String?): String? {
+ private fun formatRoomMemberEvent(event: Event, senderName: String?, rs: RoomSummary?): String? {
val eventContent: RoomMemberContent? = event.getClearContent().toModel()
val prevEventContent: RoomMemberContent? = event.resolvedPrevContent().toModel()
val isMembershipEvent = prevEventContent?.membership != eventContent?.membership
|| eventContent?.membership == Membership.LEAVE
return if (isMembershipEvent) {
- buildMembershipNotice(event, senderName, eventContent, prevEventContent)
+ buildMembershipNotice(event, senderName, eventContent, prevEventContent, rs)
} else {
buildProfileNotice(event, senderName, eventContent, prevEventContent)
}
@@ -387,20 +402,26 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
- private fun formatRoomGuestAccessEvent(event: Event, senderName: String?): String? {
+ private fun formatRoomGuestAccessEvent(event: Event, senderName: String?, rs: RoomSummary?): 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)
+ sp.getString(
+ if (rs.isDm()) R.string.notice_direct_room_guest_access_can_join_by_you else R.string.notice_room_guest_access_can_join_by_you
+ )
} else {
- sp.getString(R.string.notice_room_guest_access_can_join, senderName)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_guest_access_can_join else 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)
+ sp.getString(
+ if (rs.isDm()) R.string.notice_direct_room_guest_access_forbidden_by_you else R.string.notice_room_guest_access_forbidden_by_you
+ )
} else {
- sp.getString(R.string.notice_room_guest_access_forbidden, senderName)
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_guest_access_forbidden else R.string.notice_room_guest_access_forbidden,
+ senderName)
}
else -> null
}
@@ -476,7 +497,11 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
return displayText.toString()
}
- private fun buildMembershipNotice(event: Event, senderName: String?, eventContent: RoomMemberContent?, prevEventContent: RoomMemberContent?): String? {
+ private fun buildMembershipNotice(event: Event,
+ senderName: String?,
+ eventContent: RoomMemberContent?,
+ prevEventContent: RoomMemberContent?,
+ rs: RoomSummary?): String? {
val senderDisplayName = senderName ?: event.senderId ?: ""
val targetDisplayName = eventContent?.displayName ?: prevEventContent?.displayName ?: event.stateKey ?: ""
return when (eventContent?.membership) {
@@ -524,14 +549,21 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
Membership.JOIN ->
- 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)
+ eventContent.safeReason?.let { reason ->
+ if (event.isSentByCurrentUser()) {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_join_with_reason_by_you else R.string.notice_room_join_with_reason_by_you,
+ reason)
+ } else {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_join_with_reason else R.string.notice_room_join_with_reason,
+ senderDisplayName, reason)
+ }
+ } ?: run {
+ if (event.isSentByCurrentUser()) {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_join_by_you else R.string.notice_room_join_by_you)
+ } else {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_join else 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
@@ -548,14 +580,27 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
} ?: 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)
+ eventContent.safeReason?.let { reason ->
+ if (event.isSentByCurrentUser()) {
+ sp.getString(
+ if (rs.isDm()) {
+ R.string.notice_direct_room_leave_with_reason_by_you
+ } else {
+ R.string.notice_room_leave_with_reason_by_you
+ },
+ reason
+ )
+ } else {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_leave_with_reason else R.string.notice_room_leave_with_reason,
+ senderDisplayName, reason)
+ }
+ } ?: run {
+ if (event.isSentByCurrentUser()) {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_leave_by_you else R.string.notice_room_leave_by_you)
+ } else {
+ sp.getString(if (rs.isDm()) R.string.notice_direct_room_leave else R.string.notice_room_leave,
+ senderDisplayName)
+ }
}
}
} else {
@@ -618,14 +663,15 @@ class NoticeEventFormatter @Inject constructor(private val activeSessionDataSour
}
}
- private fun formatJoinRulesEvent(event: Event, senderName: String?): CharSequence? {
+ private fun formatJoinRulesEvent(event: Event, senderName: String?, rs: RoomSummary?): 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)
+ sp.getString(if (rs.isDm()) R.string.direct_room_join_rules_invite_by_you else R.string.room_join_rules_invite_by_you)
} else {
- sp.getString(R.string.room_join_rules_invite, senderName)
+ sp.getString(if (rs.isDm()) R.string.direct_room_join_rules_invite else R.string.room_join_rules_invite,
+ senderName)
}
RoomJoinRules.PUBLIC ->
if (event.isSentByCurrentUser()) {
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BasedMergedItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BasedMergedItem.kt
index d9dcc98ed1..1f8ad3df1b 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BasedMergedItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BasedMergedItem.kt
@@ -62,7 +62,8 @@ abstract class BasedMergedItem : BaseEventItem()
val eventId: String,
val userId: String,
val memberName: String,
- val avatarUrl: String?
+ val avatarUrl: String?,
+ val isDirectRoom: Boolean
)
fun Data.toMatrixItem() = MatrixItem.UserItem(userId, memberName, avatarUrl)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
index dad5f99eeb..1896a812fc 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MergedRoomCreationItem.kt
@@ -48,9 +48,17 @@ abstract class MergedRoomCreationItem : BasedMergedItem"Due to missing permissions, this action is not possible.
You need permission to invite to start a conference in this room
You do not have permission to start a conference call in this room
+ You do not have permission to start a conference call
You do not have permission to start a call in this room
+ You do not have permission to start a call
A conference is already in progress!
Start video meeting
Start audio meeting
@@ -1881,6 +1883,8 @@
You made the room public to whoever knows the link.
%1$s made the room invite only.
You made the room invite only.
+ %1$s made this invite only.
+ You made this invite only.
Unread messages
It\'s your conversation. Own it.
@@ -2113,12 +2117,15 @@
Waiting for %s…
For extra security, verify %s by checking a one-time code on both your devices.\n\nFor maximum security, do this in person.
Messages in this room are not end-to-end encrypted.
+ Messages here are not end-to-end encrypted.
Messages in this room are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them.
+ Messages here are end-to-end encrypted.\n\nYour messages are secured with locks and only you and the recipient have the unique keys to unlock them.
Security
Learn more
More
Admin Actions
Room settings
+ Settings
Notifications
- "One person"
@@ -2126,6 +2133,7 @@
Uploads
Leave Room
+ Leave
"Leaving the room…"
Admins
@@ -2355,11 +2363,14 @@
Encryption enabled
Messages in this room are end-to-end encrypted. Learn more & verify users in their profile.
+ Messages in this room are end-to-end encrypted.
Encryption not enabled
The encryption used by this room is not supported
%s created and configured the room.
You created and configured the room.
+ %s joined.
+ You joined.
Almost there! Is the other device showing the same shield?
Almost there! Waiting for confirmation…