mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-06 12:28:29 +00:00
Thread Decorator (#1686)
* just added the isThreaded property to message based events * done but I should add a bunch of tests for images and videos and locations * handling for image and videos, but locations might need to be double checked * code improvement * better tests and removed code that is not used, we need to fix first the appearence of replies * bubble style is solved, we now need plain style * also added plain style * better handling for bubble style * rounded corner only for bubbles in location * fix for wrong aspect ratio in replies * all changes done * better testing * swift format * changelog * PR comments and rebase. * Simplify corner radius on location timeline view. --------- Co-authored-by: Doug <douglase@element.io>
This commit is contained in:
@@ -24,6 +24,7 @@ enum RoomTimelineItemFixtures {
|
||||
timestamp: "10:10 AM",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "", displayName: "Jacob"),
|
||||
content: .init(body: "That looks so good!"),
|
||||
properties: RoomTimelineItemProperties(isEdited: true)),
|
||||
@@ -31,6 +32,7 @@ enum RoomTimelineItemFixtures {
|
||||
timestamp: "10:11 AM",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
isThreaded: false,
|
||||
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: [
|
||||
@@ -40,6 +42,7 @@ enum RoomTimelineItemFixtures {
|
||||
timestamp: "10:11 AM",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
isThreaded: false,
|
||||
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: [
|
||||
@@ -57,6 +60,7 @@ enum RoomTimelineItemFixtures {
|
||||
timestamp: "5 PM",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
isThreaded: false,
|
||||
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!"),
|
||||
properties: RoomTimelineItemProperties(orderedReadReceipts: [ReadReceipt(userID: "alice", formattedTimestamp: nil)])),
|
||||
@@ -64,12 +68,14 @@ enum RoomTimelineItemFixtures {
|
||||
timestamp: "5 PM",
|
||||
isOutgoing: true,
|
||||
isEditable: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "", displayName: "Bob"),
|
||||
content: .init(body: "And John's speech was amazing!")),
|
||||
TextRoomTimelineItem(id: .random,
|
||||
timestamp: "5 PM",
|
||||
isOutgoing: true,
|
||||
isEditable: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "", displayName: "Bob"),
|
||||
content: .init(body: "New home office set up!"),
|
||||
properties: RoomTimelineItemProperties(reactions: AggregatedReaction.mockReactions,
|
||||
@@ -81,6 +87,7 @@ enum RoomTimelineItemFixtures {
|
||||
timestamp: "5 PM",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "", displayName: "Helena"),
|
||||
content: .init(body: "",
|
||||
formattedBody: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL).fromHTML("Hol' up <blockquote>New home office set up!</blockquote>That's amazing! Congrats 🥳")))
|
||||
@@ -230,6 +237,7 @@ private extension TextRoomTimelineItem {
|
||||
timestamp: "10:47 am",
|
||||
isOutgoing: senderDisplayName == "Alice",
|
||||
isEditable: false,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "", displayName: senderDisplayName),
|
||||
content: .init(body: text))
|
||||
}
|
||||
|
||||
+1
@@ -30,4 +30,5 @@ enum EventBasedMessageTimelineItemContentType: Hashable {
|
||||
protocol EventBasedMessageTimelineItemProtocol: EventBasedTimelineItemProtocol {
|
||||
var replyDetails: TimelineItemReplyDetails? { get }
|
||||
var contentType: EventBasedMessageTimelineItemContentType { get }
|
||||
var isThreaded: Bool { get }
|
||||
}
|
||||
|
||||
+1
@@ -21,6 +21,7 @@ struct AudioRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable {
|
||||
let timestamp: String
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
let isThreaded: Bool
|
||||
let sender: TimelineItemSender
|
||||
|
||||
let content: AudioRoomTimelineItemContent
|
||||
|
||||
+1
@@ -21,6 +21,7 @@ struct EmoteRoomTimelineItem: TextBasedRoomTimelineItem, Equatable {
|
||||
let timestamp: String
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
|
||||
+2
@@ -23,6 +23,8 @@ struct FileRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable {
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
let content: FileRoomTimelineItemContent
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ struct ImageRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable {
|
||||
let timestamp: String
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ struct LocationRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatabl
|
||||
let timestamp: String
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
let content: LocationRoomTimelineItemContent
|
||||
|
||||
+1
@@ -21,6 +21,7 @@ struct NoticeRoomTimelineItem: TextBasedRoomTimelineItem, Equatable {
|
||||
let timestamp: String
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
|
||||
+2
@@ -23,6 +23,8 @@ struct TextRoomTimelineItem: TextBasedRoomTimelineItem, Equatable {
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
let content: TextRoomTimelineItemContent
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ struct VideoRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable {
|
||||
let timestamp: String
|
||||
let isOutgoing: Bool
|
||||
let isEditable: Bool
|
||||
let isThreaded: Bool
|
||||
|
||||
let sender: TimelineItemSender
|
||||
|
||||
|
||||
@@ -80,23 +80,24 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
fatalError("Invalid message timeline item: \(eventItemProxy)")
|
||||
}
|
||||
|
||||
let isThreaded = messageTimelineItem.isThreaded()
|
||||
switch messageTimelineItem.msgtype() {
|
||||
case .text(content: let content):
|
||||
return buildTextTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildTextTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .image(content: let content):
|
||||
return buildImageTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildImageTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .video(let content):
|
||||
return buildVideoTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildVideoTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .file(let content):
|
||||
return buildFileTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildFileTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .notice(content: let content):
|
||||
return buildNoticeTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildNoticeTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .emote(content: let content):
|
||||
return buildEmoteTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildEmoteTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .audio(let content):
|
||||
return buildAudioTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildAudioTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .location(let content):
|
||||
return buildLocationTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing)
|
||||
return buildLocationTimelineItem(for: eventItemProxy, messageTimelineItem, content, isOutgoing, isThreaded)
|
||||
case .none:
|
||||
return nil
|
||||
}
|
||||
@@ -182,11 +183,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildTextTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: TextMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
TextRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildTextTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -199,11 +202,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildImageTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: ImageMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
ImageRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildImageTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -216,11 +221,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildVideoTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: VideoMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
VideoRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildVideoTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -233,11 +240,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildAudioTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: AudioMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
AudioRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildAudioTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -250,11 +259,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildFileTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: FileMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
FileRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildFileTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -267,11 +278,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildNoticeTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: NoticeMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
NoticeRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildNoticeTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -284,11 +297,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildEmoteTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: EmoteMessageContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
EmoteRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildEmoteTimelineItemContent(senderDisplayName: eventItemProxy.sender.displayName, senderID: eventItemProxy.sender.id, messageContent: messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
@@ -301,11 +316,13 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
private func buildLocationTimelineItem(for eventItemProxy: EventTimelineItemProxy,
|
||||
_ messageTimelineItem: Message,
|
||||
_ messageContent: LocationContent,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ isThreaded: Bool) -> RoomTimelineItemProtocol {
|
||||
LocationRoomTimelineItem(id: eventItemProxy.id,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
isThreaded: isThreaded,
|
||||
sender: eventItemProxy.sender,
|
||||
content: buildLocationTimelineItemContent(messageContent),
|
||||
replyDetails: buildReplyToDetailsFrom(details: messageTimelineItem.inReplyTo()),
|
||||
|
||||
Reference in New Issue
Block a user