Better identification system for virtual items (#1361)

* better identification system

* better handling for unknown
This commit is contained in:
Mauro
2023-07-19 16:29:56 +02:00
committed by GitHub
parent df58d8378e
commit caeb86e178
26 changed files with 82 additions and 75 deletions
@@ -215,7 +215,7 @@ struct MessageComposer_Previews: PreviewProvider {
MessageComposer(text: .constant("Some message"), MessageComposer(text: .constant("Some message"),
focused: .constant(false), focused: .constant(false),
sendingDisabled: false, sendingDisabled: false,
mode: .edit(originalItemId: .init(timelineID: UUID().uuidString)), mode: .edit(originalItemId: .random),
sendAction: { }, sendAction: { },
pasteAction: { _ in }, pasteAction: { _ in },
replyCancellationAction: { }, replyCancellationAction: { },
@@ -224,7 +224,7 @@ struct MessageComposer_Previews: PreviewProvider {
MessageComposer(text: .constant(""), MessageComposer(text: .constant(""),
focused: .constant(false), focused: .constant(false),
sendingDisabled: false, sendingDisabled: false,
mode: .reply(itemID: .init(timelineID: UUID().uuidString), mode: .reply(itemID: .random,
replyDetails: .loaded(sender: .init(id: "Kirk"), replyDetails: .loaded(sender: .init(id: "Kirk"),
contentType: .text(.init(body: "Text: Where the wild things are")))), contentType: .text(.init(body: "Text: Where the wild things are")))),
sendAction: { }, sendAction: { },
@@ -256,7 +256,7 @@ struct MessageComposer_Previews: PreviewProvider {
MessageComposer(text: .constant(""), MessageComposer(text: .constant(""),
focused: .constant(false), focused: .constant(false),
sendingDisabled: false, sendingDisabled: false,
mode: .reply(itemID: .init(timelineID: UUID().uuidString), mode: .reply(itemID: .random,
replyDetails: replyDetails), replyDetails: replyDetails),
sendAction: { }, sendAction: { },
pasteAction: { _ in }, pasteAction: { _ in },
@@ -38,7 +38,7 @@ struct TimelineStyler<Content: View>: View {
struct TimelineItemStyler_Previews: PreviewProvider { struct TimelineItemStyler_Previews: PreviewProvider {
static let viewModel = RoomScreenViewModel.mock static let viewModel = RoomScreenViewModel.mock
static let base = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test")) static let base = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
static let sentNonLast: TextRoomTimelineItem = { static let sentNonLast: TextRoomTimelineItem = {
var result = base var result = base
@@ -71,17 +71,17 @@ struct TimelineItemStyler_Previews: PreviewProvider {
return result return result
}() }()
static let ltrString = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house!")) static let ltrString = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house!"))
static let rtlString = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת!")) static let rtlString = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת!"))
static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת‏! -- house!")) static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת‏! -- house!"))
static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת‏! -- house! -- באמת!")) static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת‏! -- house! -- באמת!"))
static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת!")) static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת!"))
static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת‏! -- house!")) static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת‏! -- house!"))
static var testView: some View { static var testView: some View {
VStack { VStack {
@@ -78,7 +78,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider {
ReadReceipt(userID: RoomMemberProxyMock.mockDan.userID, formattedTimestamp: "Way, way before")] ReadReceipt(userID: RoomMemberProxyMock.mockDan.userID, formattedTimestamp: "Way, way before")]
static func mockTimelineItem(with receipts: [ReadReceipt]) -> TextRoomTimelineItem { static func mockTimelineItem(with receipts: [ReadReceipt]) -> TextRoomTimelineItem {
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: true, isOutgoing: true,
isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"), isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"),
@@ -44,7 +44,7 @@ struct AudioRoomTimelineView_Previews: PreviewProvider {
} }
static var body: some View { static var body: some View {
AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: .init(timelineID: UUID().uuidString), AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -55,7 +55,7 @@ struct EmoteRoomTimelineView_Previews: PreviewProvider {
} }
private static func itemWith(text: String, timestamp: String, senderId: String) -> EmoteRoomTimelineItem { private static func itemWith(text: String, timestamp: String, senderId: String) -> EmoteRoomTimelineItem {
EmoteRoomTimelineItem(id: .init(timelineID: UUID().uuidString), EmoteRoomTimelineItem(id: .random,
timestamp: timestamp, timestamp: timestamp,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -55,7 +55,7 @@ private struct EncryptedHistoryLabelStyle: LabelStyle {
struct EncryptedHistoryRoomTimelineView_Previews: PreviewProvider { struct EncryptedHistoryRoomTimelineView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
let item = EncryptedHistoryRoomTimelineItem(id: .init(timelineID: UUID().uuidString)) let item = EncryptedHistoryRoomTimelineItem(id: .random)
EncryptedHistoryRoomTimelineView(timelineItem: item) EncryptedHistoryRoomTimelineView(timelineItem: item)
} }
} }
@@ -67,7 +67,7 @@ struct EncryptedRoomTimelineView_Previews: PreviewProvider {
} }
private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> EncryptedRoomTimelineItem { private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> EncryptedRoomTimelineItem {
EncryptedRoomTimelineItem(id: .init(timelineID: UUID().uuidString), EncryptedRoomTimelineItem(id: .random,
body: text, body: text,
encryptionType: .unknown, encryptionType: .unknown,
timestamp: timestamp, timestamp: timestamp,
@@ -45,21 +45,21 @@ struct FileRoomTimelineView_Previews: PreviewProvider {
static var body: some View { static var body: some View {
VStack(spacing: 20.0) { VStack(spacing: 20.0) {
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString), FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "document.pdf", source: nil, thumbnailSource: nil, contentType: nil))) content: .init(body: "document.pdf", source: nil, thumbnailSource: nil, contentType: nil)))
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString), FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "document.docx", source: nil, thumbnailSource: nil, contentType: nil))) content: .init(body: "document.docx", source: nil, thumbnailSource: nil, contentType: nil)))
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString), FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -66,21 +66,21 @@ struct ImageRoomTimelineView_Previews: PreviewProvider {
static var body: some View { static var body: some View {
VStack(spacing: 20.0) { VStack(spacing: 20.0) {
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .init(timelineID: UUID().uuidString), ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil))) content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil)))
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .init(timelineID: UUID().uuidString), ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "Some other image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil))) content: .init(body: "Some other image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil)))
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .init(timelineID: UUID().uuidString), ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -91,14 +91,14 @@ struct LocationRoomTimelineView_Previews: PreviewProvider {
@ViewBuilder @ViewBuilder
static var body: some View { static var body: some View {
LocationRoomTimelineView(timelineItem: .init(id: .init(timelineID: UUID().uuidString), LocationRoomTimelineView(timelineItem: .init(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "Fallback geo uri description"))) content: .init(body: "Fallback geo uri description")))
LocationRoomTimelineView(timelineItem: .init(id: .init(timelineID: UUID().uuidString), LocationRoomTimelineView(timelineItem: .init(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -66,7 +66,7 @@ struct NoticeRoomTimelineView_Previews: PreviewProvider {
} }
private static func itemWith(text: String, timestamp: String, senderId: String) -> NoticeRoomTimelineItem { private static func itemWith(text: String, timestamp: String, senderId: String) -> NoticeRoomTimelineItem {
NoticeRoomTimelineItem(id: .init(timelineID: UUID().uuidString), NoticeRoomTimelineItem(id: .random,
timestamp: timestamp, timestamp: timestamp,
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -38,7 +38,8 @@ struct ReadMarkerRoomTimelineView: View {
struct ReadMarkerRoomTimelineView_Previews: PreviewProvider { struct ReadMarkerRoomTimelineView_Previews: PreviewProvider {
static let viewModel = RoomScreenViewModel.mock static let viewModel = RoomScreenViewModel.mock
static let item = ReadMarkerRoomTimelineItem() static let item = ReadMarkerRoomTimelineItem(id: .init(timelineID: .init(UUID().uuidString)))
static var previews: some View { static var previews: some View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
RoomTimelineItemView(viewModel: .init(type: .separator(.init(id: .init(timelineID: "Separator"), text: "Today")), groupStyle: .single)) RoomTimelineItemView(viewModel: .init(type: .separator(.init(id: .init(timelineID: "Separator"), text: "Today")), groupStyle: .single))
@@ -42,7 +42,7 @@ struct RedactedRoomTimelineView_Previews: PreviewProvider {
} }
private static func itemWith(text: String, timestamp: String, senderId: String) -> RedactedRoomTimelineItem { private static func itemWith(text: String, timestamp: String, senderId: String) -> RedactedRoomTimelineItem {
RedactedRoomTimelineItem(id: .init(timelineID: UUID().uuidString), RedactedRoomTimelineItem(id: .random,
body: text, body: text,
timestamp: timestamp, timestamp: timestamp,
isOutgoing: false, isOutgoing: false,
@@ -41,7 +41,7 @@ struct StateRoomTimelineView_Previews: PreviewProvider {
StateRoomTimelineView(timelineItem: item) StateRoomTimelineView(timelineItem: item)
} }
static let item = StateRoomTimelineItem(id: .init(timelineID: UUID().uuidString), static let item = StateRoomTimelineItem(id: .random,
body: "Alice joined", body: "Alice joined",
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
@@ -58,7 +58,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider {
static var body: some View { static var body: some View {
VStack(spacing: 20.0) { VStack(spacing: 20.0) {
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .init(timelineID: UUID().uuidString), StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .random,
body: "Some image", body: "Some image",
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
@@ -66,7 +66,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider {
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
imageURL: URL.picturesDirectory)) imageURL: URL.picturesDirectory))
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .init(timelineID: UUID().uuidString), StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .random,
body: "Some other image", body: "Some other image",
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
@@ -74,7 +74,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider {
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
imageURL: URL.picturesDirectory)) imageURL: URL.picturesDirectory))
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .init(timelineID: UUID().uuidString), StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .random,
body: "Blurhashed image", body: "Blurhashed image",
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
@@ -71,7 +71,7 @@ struct TextRoomTimelineView_Previews: PreviewProvider {
} }
private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> TextRoomTimelineItem { private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> TextRoomTimelineItem {
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: timestamp, timestamp: timestamp,
isOutgoing: isOutgoing, isOutgoing: isOutgoing,
isEditable: isOutgoing, isEditable: isOutgoing,
@@ -63,7 +63,7 @@ struct UnsupportedRoomTimelineView_Previews: PreviewProvider {
} }
private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> UnsupportedRoomTimelineItem { private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> UnsupportedRoomTimelineItem {
UnsupportedRoomTimelineItem(id: .init(timelineID: UUID().uuidString), UnsupportedRoomTimelineItem(id: .random,
body: text, body: text,
eventType: "Some Event Type", eventType: "Some Event Type",
error: "Something went wrong", error: "Something went wrong",
@@ -77,21 +77,21 @@ struct VideoRoomTimelineView_Previews: PreviewProvider {
static var body: some View { static var body: some View {
VStack(spacing: 20.0) { VStack(spacing: 20.0) {
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString), VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "Some video", duration: 21, source: nil, thumbnailSource: nil))) content: .init(body: "Some video", duration: 21, source: nil, thumbnailSource: nil)))
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString), VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "Bob"), sender: .init(id: "Bob"),
content: .init(body: "Some other video", duration: 22, source: nil, thumbnailSource: nil))) content: .init(body: "Some other video", duration: 22, source: nil, thumbnailSource: nil)))
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString), VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .random,
timestamp: "Now", timestamp: "Now",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -20,14 +20,14 @@ enum RoomTimelineItemFixtures {
/// The default timeline items used in Xcode previews etc. /// The default timeline items used in Xcode previews etc.
static var `default`: [RoomTimelineItemProtocol] = [ static var `default`: [RoomTimelineItemProtocol] = [
SeparatorRoomTimelineItem(id: .init(timelineID: "Yesterday"), text: "Yesterday"), SeparatorRoomTimelineItem(id: .init(timelineID: "Yesterday"), text: "Yesterday"),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "10:10 AM", timestamp: "10:10 AM",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "", displayName: "Jacob"), sender: .init(id: "", displayName: "Jacob"),
content: .init(body: "That looks so good!"), content: .init(body: "That looks so good!"),
properties: RoomTimelineItemProperties(isEdited: true)), properties: RoomTimelineItemProperties(isEdited: true)),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "10:11 AM", timestamp: "10:11 AM",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -36,7 +36,7 @@ enum RoomTimelineItemFixtures {
properties: RoomTimelineItemProperties(reactions: [ properties: RoomTimelineItemProperties(reactions: [
AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(senderID: "me", timestamp: Date())]) AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(senderID: "me", timestamp: Date())])
])), ])),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "10:11 AM", timestamp: "10:11 AM",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -53,20 +53,20 @@ enum RoomTimelineItemFixtures {
]) ])
])), ])),
SeparatorRoomTimelineItem(id: .init(timelineID: "Today"), text: "Today"), SeparatorRoomTimelineItem(id: .init(timelineID: "Today"), text: "Today"),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "5 PM", timestamp: "5 PM",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "", displayName: "Helena"), sender: .init(id: "", displayName: "Helena"),
content: .init(body: "Wow, cool. Ok, lets go the usual place tomorrow?! Is that too soon? Here’s the menu, let me know what you want it’s on me!"), content: .init(body: "Wow, cool. Ok, lets go the usual place tomorrow?! Is that too soon? Here’s the menu, let me know what you want it’s on me!"),
properties: RoomTimelineItemProperties(orderedReadReceipts: [ReadReceipt(userID: "alice", formattedTimestamp: nil)])), properties: RoomTimelineItemProperties(orderedReadReceipts: [ReadReceipt(userID: "alice", formattedTimestamp: nil)])),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "5 PM", timestamp: "5 PM",
isOutgoing: true, isOutgoing: true,
isEditable: true, isEditable: true,
sender: .init(id: "", displayName: "Bob"), sender: .init(id: "", displayName: "Bob"),
content: .init(body: "And John's speech was amazing!")), content: .init(body: "And John's speech was amazing!")),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "5 PM", timestamp: "5 PM",
isOutgoing: true, isOutgoing: true,
isEditable: true, isEditable: true,
@@ -77,7 +77,7 @@ enum RoomTimelineItemFixtures {
ReadReceipt(userID: "bob", formattedTimestamp: nil), ReadReceipt(userID: "bob", formattedTimestamp: nil),
ReadReceipt(userID: "charlie", formattedTimestamp: nil), ReadReceipt(userID: "charlie", formattedTimestamp: nil),
ReadReceipt(userID: "dan", formattedTimestamp: nil)])), ReadReceipt(userID: "dan", formattedTimestamp: nil)])),
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), TextRoomTimelineItem(id: .random,
timestamp: "5 PM", timestamp: "5 PM",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -216,7 +216,7 @@ enum RoomTimelineItemFixtures {
private extension TextRoomTimelineItem { private extension TextRoomTimelineItem {
init(text: String, senderDisplayName: String) { init(text: String, senderDisplayName: String) {
self.init(id: .init(timelineID: UUID().uuidString), self.init(id: .random,
timestamp: "10:47 am", timestamp: "10:47 am",
isOutgoing: senderDisplayName == "Alice", isOutgoing: senderDisplayName == "Alice",
isEditable: false, isEditable: false,
@@ -171,14 +171,14 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
private extension TimelineItem { private extension TimelineItem {
var debugIdentifier: DebugIdentifier { var debugIdentifier: DebugIdentifier {
if let virtualTimelineItem = asVirtual() { if let virtualTimelineItem = asVirtual() {
return virtualTimelineItem.debugIdentifier return .virtual(timelineID: String(uniqueId()), dscription: virtualTimelineItem.description)
} else if let eventTimelineItem = asEvent() { } else if let eventTimelineItem = asEvent() {
return .event(timelineID: String(uniqueId()), return .event(timelineID: String(uniqueId()),
eventID: eventTimelineItem.eventId(), eventID: eventTimelineItem.eventId(),
transactionID: eventTimelineItem.transactionId()) transactionID: eventTimelineItem.transactionId())
} }
return .unknown return .unknown(timelineID: String(uniqueId()))
} }
} }
@@ -189,27 +189,27 @@ private extension TimelineItemProxy {
return .event(timelineID: eventTimelineItem.id.timelineID, return .event(timelineID: eventTimelineItem.id.timelineID,
eventID: eventTimelineItem.id.eventID, eventID: eventTimelineItem.id.eventID,
transactionID: eventTimelineItem.id.transactionID) transactionID: eventTimelineItem.id.transactionID)
case .virtual(let virtualTimelineItem): case .virtual(let virtualTimelineItem, let timelineID):
return virtualTimelineItem.debugIdentifier return .virtual(timelineID: timelineID, dscription: virtualTimelineItem.description)
case .unknown: case .unknown(let item):
return .unknown return .unknown(timelineID: String(item.uniqueId()))
} }
} }
} }
private extension VirtualTimelineItem { private extension VirtualTimelineItem {
var debugIdentifier: DebugIdentifier { var description: String {
switch self { switch self {
case .dayDivider(let timestamp): case .dayDivider(let timestamp):
return .virtual("DayDiviver(\(timestamp))") return "DayDiviver(\(timestamp))"
case .readMarker: case .readMarker:
return .virtual("ReadMarker") return "ReadMarker"
} }
} }
} }
enum DebugIdentifier { enum DebugIdentifier {
case event(timelineID: String?, eventID: String?, transactionID: String?) case event(timelineID: String, eventID: String?, transactionID: String?)
case virtual(String) case virtual(timelineID: String, dscription: String)
case unknown case unknown(timelineID: String)
} }
@@ -349,16 +349,15 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
} }
return timelineItem return timelineItem
case .virtual(let virtualItem): case .virtual(let virtualItem, let timelineID):
switch virtualItem { switch virtualItem {
case .dayDivider(let timestamp): case .dayDivider(let timestamp):
let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000)) let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000))
let dateString = date.formatted(date: .complete, time: .omitted) let dateString = date.formatted(date: .complete, time: .omitted)
let identifier = date.formatted(.iso8601.dateSeparator(.dash)) return SeparatorRoomTimelineItem(id: .init(timelineID: timelineID), text: dateString)
return SeparatorRoomTimelineItem(id: .init(timelineID: identifier), text: dateString)
case .readMarker: case .readMarker:
return ReadMarkerRoomTimelineItem() return ReadMarkerRoomTimelineItem(id: .init(timelineID: timelineID))
} }
case .unknown: case .unknown:
return nil return nil
@@ -31,17 +31,24 @@ struct TimelineItemIdentifier: Hashable {
var transactionID: String? var transactionID: String?
} }
extension TimelineItemIdentifier {
/// Use only for mocks/tests
static var random: Self {
.init(timelineID: UUID().uuidString)
}
}
/// A light wrapper around timeline items returned from Rust. /// A light wrapper around timeline items returned from Rust.
enum TimelineItemProxy { enum TimelineItemProxy {
case event(EventTimelineItemProxy) case event(EventTimelineItemProxy)
case virtual(MatrixRustSDK.VirtualTimelineItem) case virtual(MatrixRustSDK.VirtualTimelineItem, timelineID: String)
case unknown(MatrixRustSDK.TimelineItem) case unknown(MatrixRustSDK.TimelineItem)
init(item: MatrixRustSDK.TimelineItem) { init(item: MatrixRustSDK.TimelineItem) {
if let eventItem = item.asEvent() { if let eventItem = item.asEvent() {
self = .event(EventTimelineItemProxy(item: eventItem, id: item.uniqueId())) self = .event(EventTimelineItemProxy(item: eventItem, id: item.uniqueId()))
} else if let virtualItem = item.asVirtual() { } else if let virtualItem = item.asVirtual() {
self = .virtual(virtualItem) self = .virtual(virtualItem, timelineID: String(item.uniqueId()))
} else { } else {
self = .unknown(item) self = .unknown(item)
} }
@@ -17,5 +17,5 @@
import Foundation import Foundation
struct ReadMarkerRoomTimelineItem: DecorationTimelineItemProtocol, Equatable { struct ReadMarkerRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
let id = TimelineItemIdentifier(timelineID: "readMarkerTimelineItemIdentifier") let id: TimelineItemIdentifier
} }
+5 -5
View File
@@ -252,21 +252,21 @@ class LoggingTests: XCTestCase {
func testTimelineContentIsRedacted() throws { func testTimelineContentIsRedacted() throws {
// Given timeline items that contain text // Given timeline items that contain text
let textAttributedString = "TextAttributed" let textAttributedString = "TextAttributed"
let textMessage = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), let textMessage = TextRoomTimelineItem(id: .random,
timestamp: "", timestamp: "",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "sender"), sender: .init(id: "sender"),
content: .init(body: "TextString", formattedBody: AttributedString(textAttributedString))) content: .init(body: "TextString", formattedBody: AttributedString(textAttributedString)))
let noticeAttributedString = "NoticeAttributed" let noticeAttributedString = "NoticeAttributed"
let noticeMessage = NoticeRoomTimelineItem(id: .init(timelineID: UUID().uuidString), let noticeMessage = NoticeRoomTimelineItem(id: .random,
timestamp: "", timestamp: "",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "sender"), sender: .init(id: "sender"),
content: .init(body: "NoticeString", formattedBody: AttributedString(noticeAttributedString))) content: .init(body: "NoticeString", formattedBody: AttributedString(noticeAttributedString)))
let emoteAttributedString = "EmoteAttributed" let emoteAttributedString = "EmoteAttributed"
let emoteMessage = EmoteRoomTimelineItem(id: .init(timelineID: UUID().uuidString), let emoteMessage = EmoteRoomTimelineItem(id: .random,
timestamp: "", timestamp: "",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -278,13 +278,13 @@ class LoggingTests: XCTestCase {
isEditable: false, isEditable: false,
sender: .init(id: "sender"), sender: .init(id: "sender"),
content: .init(body: "ImageString", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/gif"), thumbnailSource: nil)) content: .init(body: "ImageString", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/gif"), thumbnailSource: nil))
let videoMessage = VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString), let videoMessage = VideoRoomTimelineItem(id: .random,
timestamp: "", timestamp: "",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
sender: .init(id: "sender"), sender: .init(id: "sender"),
content: .init(body: "VideoString", duration: 0, source: nil, thumbnailSource: nil)) content: .init(body: "VideoString", duration: 0, source: nil, thumbnailSource: nil))
let fileMessage = FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString), let fileMessage = FileRoomTimelineItem(id: .random,
timestamp: "", timestamp: "",
isOutgoing: false, isOutgoing: false,
isEditable: false, isEditable: false,
@@ -309,7 +309,7 @@ class RoomScreenViewModelTests: XCTestCase {
userIndicatorController: userIndicatorControllerMock) userIndicatorController: userIndicatorControllerMock)
// Test // Test
viewModel.context.send(viewAction: .retrySend(itemID: .init(timelineID: UUID().uuidString))) viewModel.context.send(viewAction: .retrySend(itemID: .random))
await Task.yield() await Task.yield()
XCTAssert(roomProxyMock.retrySendTransactionIDCallsCount == 0) XCTAssert(roomProxyMock.retrySendTransactionIDCallsCount == 0)
} }
@@ -346,7 +346,7 @@ class RoomScreenViewModelTests: XCTestCase {
userIndicatorController: userIndicatorControllerMock) userIndicatorController: userIndicatorControllerMock)
// Test // Test
viewModel.context.send(viewAction: .cancelSend(itemID: .init(timelineID: UUID().uuidString))) viewModel.context.send(viewAction: .cancelSend(itemID: .random))
await Task.yield() await Task.yield()
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0) XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0)
} }
@@ -376,7 +376,7 @@ class RoomScreenViewModelTests: XCTestCase {
private extension TextRoomTimelineItem { private extension TextRoomTimelineItem {
init(text: String, sender: String, addReactions: Bool = false) { init(text: String, sender: String, addReactions: Bool = false) {
let reactions = addReactions ? [AggregatedReaction(accountOwnerID: "bob", key: "🦄", senders: [ReactionSender(senderID: sender, timestamp: Date())])] : [] let reactions = addReactions ? [AggregatedReaction(accountOwnerID: "bob", key: "🦄", senders: [ReactionSender(senderID: sender, timestamp: Date())])] : []
self.init(id: .init(timelineID: UUID().uuidString), self.init(id: .random,
timestamp: "10:47 am", timestamp: "10:47 am",
isOutgoing: sender == "bob", isOutgoing: sender == "bob",
isEditable: sender == "bob", isEditable: sender == "bob",
@@ -20,7 +20,7 @@ import XCTest
final class TextBasedRoomTimelineTests: XCTestCase { final class TextBasedRoomTimelineTests: XCTestCase {
func testTextRoomTimelineItemWhitespaceEnd() { func testTextRoomTimelineItemWhitespaceEnd() {
let timestamp = "Now" let timestamp = "Now"
let timelineItem = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test")) let timelineItem = TextRoomTimelineItem(id: .random, timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>() let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>()
view.underlyingTimelineItem = timelineItem view.underlyingTimelineItem = timelineItem
view.timelineStyle = .bubbles view.timelineStyle = .bubbles
@@ -30,7 +30,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
func testTextRoomTimelineItemWhitespaceEndLonger() { func testTextRoomTimelineItemWhitespaceEndLonger() {
let timestamp = "10:00 AM" let timestamp = "10:00 AM"
let timelineItem = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test")) let timelineItem = TextRoomTimelineItem(id: .random, timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>() let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>()
view.underlyingTimelineItem = timelineItem view.underlyingTimelineItem = timelineItem
view.timelineStyle = .bubbles view.timelineStyle = .bubbles
@@ -39,7 +39,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
} }
func testTextRoomTimelineItemWhitespaceEndPlain() { func testTextRoomTimelineItemWhitespaceEndPlain() {
let timelineItem = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test")) let timelineItem = TextRoomTimelineItem(id: .random, timestamp: "Now", isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>() let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>()
view.underlyingTimelineItem = timelineItem view.underlyingTimelineItem = timelineItem
view.timelineStyle = .plain view.timelineStyle = .plain
@@ -49,7 +49,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
func testTextRoomTimelineItemWhitespaceEndWithEdit() { func testTextRoomTimelineItemWhitespaceEndWithEdit() {
let timestamp = "Now" let timestamp = "Now"
var timelineItem = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test")) var timelineItem = TextRoomTimelineItem(id: .random, timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
timelineItem.properties.isEdited = true timelineItem.properties.isEdited = true
let editedCount = L10n.commonEditedSuffix.count let editedCount = L10n.commonEditedSuffix.count
let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>() let view = TextBasedRoomTimelineViewMock<TextRoomTimelineItem>()
@@ -61,7 +61,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
func testTextRoomTimelineItemWhitespaceEndWithEditAndAlert() { func testTextRoomTimelineItemWhitespaceEndWithEditAndAlert() {
let timestamp = "Now" let timestamp = "Now"
var timelineItem = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test")) var timelineItem = TextRoomTimelineItem(id: .random, timestamp: timestamp, isOutgoing: true, isEditable: true, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
timelineItem.properties.isEdited = true timelineItem.properties.isEdited = true
timelineItem.properties.deliveryStatus = .sendingFailed timelineItem.properties.deliveryStatus = .sendingFailed
let editedCount = L10n.commonEditedSuffix.count let editedCount = L10n.commonEditedSuffix.count