mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Display a badge for messages decrypted using shared keys. (#4937)
* feat: Show info badge for messages decrypted with shared keys * tests: Add snapshots and tests for forwarder icon. * fix: Update `EventBasedTimelineItemProtocol.hasStatusIcon` * fix: Address review comments. * fix: Use two translations for key forwarded dialog content. * refactor: Rename `TimelineItemForwarder` to `TimelineItemKeyForwarder`. Additionally adds a `[weak self]` guard to `encryptionForwarder` alert handler. * tests: Add `previewLayout` directive to `encryptionForwarder` previews * refactor: Remove unused translations, use short-circuiting condition.
This commit is contained in:
+2
@@ -26,4 +26,6 @@ struct RoomTimelineItemProperties: Hashable {
|
||||
var orderedReadReceipts: [ReadReceipt] = []
|
||||
/// Authenticity warnings for item's sent in encrypted rooms.
|
||||
var encryptionAuthenticity: EncryptionAuthenticity?
|
||||
/// Information about the forwarder of the keys used to decrypt this message.
|
||||
var encryptionForwarder: TimelineItemKeyForwarder?
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import MatrixRustSDK
|
||||
import SwiftUI
|
||||
|
||||
struct TimelineItemKeyForwarder: Identifiable, Hashable {
|
||||
let id: String
|
||||
let displayName: String?
|
||||
|
||||
init(id: String, displayName: String? = nil) {
|
||||
self.id = id
|
||||
self.displayName = displayName
|
||||
}
|
||||
|
||||
init(forwarderID: String, forwarderProfile: ProfileDetails) {
|
||||
switch forwarderProfile {
|
||||
case let .ready(displayName, _, _):
|
||||
self.init(id: forwarderID,
|
||||
displayName: displayName)
|
||||
default:
|
||||
self.init(id: forwarderID,
|
||||
displayName: nil)
|
||||
}
|
||||
}
|
||||
|
||||
var message: String {
|
||||
if let displayName {
|
||||
L10n.cryptoEventKeyForwardedKnownProfileDialogContent(displayName, id)
|
||||
} else {
|
||||
L10n.cryptoEventKeyForwardedUnknownProfileDialogContent(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,13 @@ class EventTimelineItemProxy {
|
||||
|
||||
lazy var sender = TimelineItemSender(senderID: item.sender, senderProfile: item.senderProfile)
|
||||
|
||||
lazy var forwarder: TimelineItemKeyForwarder? = {
|
||||
guard let forwarderID = item.forwarder, let forwarderProfile = item.forwarderProfile else {
|
||||
return nil
|
||||
}
|
||||
return TimelineItemKeyForwarder(forwarderID: forwarderID, forwarderProfile: forwarderProfile)
|
||||
}()
|
||||
|
||||
lazy var timestamp = Date(timeIntervalSince1970: TimeInterval(item.timestamp / 1000))
|
||||
|
||||
lazy var debugInfo: TimelineItemDebugInfo = {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ extension EventBasedTimelineItemProtocol {
|
||||
}
|
||||
|
||||
var hasStatusIcon: Bool {
|
||||
hasFailedToSend || properties.encryptionAuthenticity != nil
|
||||
hasFailedToSend || properties.encryptionAuthenticity != nil || properties.encryptionForwarder != nil
|
||||
}
|
||||
|
||||
var hasFailedToSend: Bool {
|
||||
|
||||
@@ -126,7 +126,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildImageTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -149,7 +150,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildVideoTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -172,7 +174,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildAudioTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -195,7 +198,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildVoiceTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -217,7 +221,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildFileTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -240,7 +245,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildNoticeTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -262,7 +268,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildEmoteTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -284,7 +291,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildLocationTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -306,7 +314,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildGalleryTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -329,7 +338,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildStickerTimelineItem(_ eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -355,7 +365,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildPollTimelineItem(_ eventItemProxy: EventTimelineItemProxy,
|
||||
@@ -415,7 +426,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
reactions: buildAggregatedReactions(messageLikeContent.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: buildOrderedReadReceipts(eventItemProxy.readReceipts),
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState)))
|
||||
encryptionAuthenticity: buildEncryptionAuthenticity(eventItemProxy.shieldState),
|
||||
encryptionForwarder: eventItemProxy.forwarder))
|
||||
}
|
||||
|
||||
private func buildRedactedTimelineItem(_ eventItemProxy: EventTimelineItemProxy,
|
||||
|
||||
Reference in New Issue
Block a user