diff --git a/ElementX/Sources/Mocks/AggregatedReactionMock.swift b/ElementX/Sources/Mocks/AggregatedReactionMock.swift index 24fea97b1..852764b44 100644 --- a/ElementX/Sources/Mocks/AggregatedReactionMock.swift +++ b/ElementX/Sources/Mocks/AggregatedReactionMock.swift @@ -26,7 +26,7 @@ extension AggregatedReaction { private static func mockReaction(key: String, senderIDs: [String]) -> AggregatedReaction { let senders = senderIDs .map { id in - ReactionSender(senderID: id, timestamp: Date(timeIntervalSinceReferenceDate: 0)) + ReactionSender(id: id, timestamp: Date(timeIntervalSinceReferenceDate: 0)) } return AggregatedReaction(accountOwnerID: alice, key: key, senders: senders) } diff --git a/ElementX/Sources/Screens/RoomScreen/View/Supplementary/ReactionsSummaryView.swift b/ElementX/Sources/Screens/RoomScreen/View/Supplementary/ReactionsSummaryView.swift index 4a533235b..53fbfc0e3 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Supplementary/ReactionsSummaryView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Supplementary/ReactionsSummaryView.swift @@ -37,11 +37,10 @@ struct ReactionsSummaryView: View { ScrollView(.horizontal, showsIndicators: false) { ScrollViewReader { scrollView in HStack(spacing: 8) { - ForEach(reactions, id: \.self) { reaction in + ForEach(reactions) { reaction in ReactionSummaryButton(reaction: reaction, highlighted: selectedReactionKey == reaction.key) { key in selectedReactionKey = key } - .id(reaction.key) } } .padding(.horizontal, 20) @@ -61,11 +60,11 @@ struct ReactionsSummaryView: View { private var sendersList: some View { TabView(selection: $selectedReactionKey) { - ForEach(reactions, id: \.self) { reaction in + ForEach(reactions) { reaction in ScrollView { VStack(alignment: .leading, spacing: 8) { - ForEach(reaction.senders, id: \.self) { sender in - ReactionSummarySenderView(sender: sender, member: members[sender.senderID], imageProvider: imageProvider) + ForEach(reaction.senders) { sender in + ReactionSummarySenderView(sender: sender, member: members[sender.id], imageProvider: imageProvider) .padding(.horizontal, 16) } } @@ -114,14 +113,14 @@ private struct ReactionSummarySenderView: View { let imageProvider: ImageProviderProtocol? var displayName: String { - member?.displayName ?? sender.senderID + member?.displayName ?? sender.id } var body: some View { HStack(spacing: 8) { LoadableAvatarImage(url: member?.avatarURL, name: displayName, - contentID: sender.senderID, + contentID: sender.id, avatarSize: .user(on: .timeline), imageProvider: imageProvider) @@ -134,7 +133,7 @@ private struct ReactionSummarySenderView: View { .font(.compound.bodyXS) .foregroundColor(.compound.textSecondary) } - Text(sender.senderID) + Text(sender.id) .font(.compound.bodySM) .foregroundColor(.compound.textSecondary) } diff --git a/ElementX/Sources/Screens/RoomScreen/View/Supplementary/TimelineReactionsView.swift b/ElementX/Sources/Screens/RoomScreen/View/Supplementary/TimelineReactionsView.swift index e3776e628..cf9445a13 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Supplementary/TimelineReactionsView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Supplementary/TimelineReactionsView.swift @@ -51,7 +51,7 @@ struct TimelineReactionsView: View { var body: some View { layout { - ForEach(reactions, id: \.self) { reaction in + ForEach(reactions) { reaction in TimelineReactionButton(reaction: reaction) { key in feedbackGenerator.impactOccurred() context.send(viewAction: .toggleReaction(key: key, itemID: itemID)) diff --git a/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift b/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift index 8be148a65..80b91411d 100644 --- a/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift +++ b/ElementX/Sources/Services/Timeline/Fixtures/RoomTimelineItemFixtures.swift @@ -38,7 +38,7 @@ enum RoomTimelineItemFixtures { sender: .init(id: "", displayName: "Helena"), content: .init(body: "Letโ€™s get lunch soon! New salad place opened up ๐Ÿฅ—. When are yโ€™all free? ๐Ÿค—"), properties: RoomTimelineItemProperties(reactions: [ - AggregatedReaction(accountOwnerID: "me", key: "๐Ÿ™Œ", senders: [ReactionSender(senderID: "me", timestamp: Date())]) + AggregatedReaction(accountOwnerID: "me", key: "๐Ÿ™Œ", senders: [ReactionSender(id: "me", timestamp: Date())]) ])), TextRoomTimelineItem(id: .random, timestamp: "10:11 AM", @@ -49,13 +49,13 @@ enum RoomTimelineItemFixtures { sender: .init(id: "", displayName: "Helena"), content: .init(body: "I can be around on Wednesday. How about some ๐ŸŒฎ instead? Like https://www.tortilla.co.uk/"), properties: RoomTimelineItemProperties(reactions: [ - AggregatedReaction(accountOwnerID: "me", key: "๐Ÿ™", senders: [ReactionSender(senderID: "helena", timestamp: Date())]), + AggregatedReaction(accountOwnerID: "me", key: "๐Ÿ™", senders: [ReactionSender(id: "helena", timestamp: Date())]), AggregatedReaction(accountOwnerID: "me", key: "๐Ÿ™Œ", senders: [ - ReactionSender(senderID: "me", timestamp: Date()), - ReactionSender(senderID: "helena", timestamp: Date()), - ReactionSender(senderID: "jacob", timestamp: Date()) + ReactionSender(id: "me", timestamp: Date()), + ReactionSender(id: "helena", timestamp: Date()), + ReactionSender(id: "jacob", timestamp: Date()) ]) ])), SeparatorRoomTimelineItem(id: .init(timelineID: "Today"), text: "Today"), diff --git a/ElementX/Sources/Services/Timeline/TimelineItemContent/AggregratedReaction.swift b/ElementX/Sources/Services/Timeline/TimelineItemContent/AggregratedReaction.swift index f5e02d41b..d17f813e6 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemContent/AggregratedReaction.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemContent/AggregratedReaction.swift @@ -17,12 +17,16 @@ import Foundation /// Represents all reactions of the same type for a single event. -struct AggregatedReaction: Hashable { +struct AggregatedReaction: Hashable, Identifiable { /// Length at which we ellipsize a reaction key for display /// Reactions can be free text, so we need to limit the length /// displayed on screen. private static let maxDisplayChars = 16 + var id: String { + key + } + /// The id of the account owner let accountOwnerID: String /// The reaction that was sent. @@ -32,9 +36,9 @@ struct AggregatedReaction: Hashable { } /// Details of who sent the reaction -struct ReactionSender: Hashable { +struct ReactionSender: Hashable, Identifiable { /// The id of the user who sent the reaction - let senderID: String + let id: String /// The time that the reaction was received on the original homeserver let timestamp: Date } @@ -47,7 +51,7 @@ extension AggregatedReaction { /// Whether to highlight the reaction, indicating that the current user sent this reaction. var isHighlighted: Bool { - senders.contains(where: { $0.senderID == accountOwnerID }) + senders.contains(where: { $0.id == accountOwnerID }) } /// The key to be displayed on screen. See `maxDisplayChars`. diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift index 378c9d76e..d9fb35136 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift @@ -418,7 +418,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { reactions.map { reaction in let senders = reaction.senders .map { senderData in - ReactionSender(senderID: senderData.senderId, timestamp: Date(timeIntervalSince1970: TimeInterval(senderData.timestamp / 1000))) + ReactionSender(id: senderData.senderId, timestamp: Date(timeIntervalSince1970: TimeInterval(senderData.timestamp / 1000))) } .sorted { a, b in // Sort reactions within an aggregation by timestamp descending. diff --git a/UnitTests/Sources/RoomScreenViewModelTests.swift b/UnitTests/Sources/RoomScreenViewModelTests.swift index 35ced21fa..cb2fa123a 100644 --- a/UnitTests/Sources/RoomScreenViewModelTests.swift +++ b/UnitTests/Sources/RoomScreenViewModelTests.swift @@ -619,7 +619,7 @@ class RoomScreenViewModelTests: XCTestCase { private extension TextRoomTimelineItem { init(text: String, sender: String, addReactions: Bool = false, addReadReceipts: [ReadReceipt] = []) { - let reactions = addReactions ? [AggregatedReaction(accountOwnerID: "bob", key: "๐Ÿฆ„", senders: [ReactionSender(senderID: sender, timestamp: Date())])] : [] + let reactions = addReactions ? [AggregatedReaction(accountOwnerID: "bob", key: "๐Ÿฆ„", senders: [ReactionSender(id: sender, timestamp: Date())])] : [] self.init(id: .random, timestamp: "10:47 am", isOutgoing: sender == "bob",