diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index ffa91beee..f3b698bb6 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -20,6 +20,12 @@ 1850257127B6A135002E6B18 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1850256927B6A135002E6B18 /* LaunchScreen.storyboard */; }; 1863A3FC27BA5A9100B52E4D /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 1863A3FB27BA5A9100B52E4D /* KeychainAccess */; }; 1863A40627BA6DFC00B52E4D /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = 1863A40527BA6DFC00B52E4D /* SwiftyBeaver */; }; + 18920C0E27F233FF00A717B5 /* NoticeRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C0C27F233FF00A717B5 /* NoticeRoomMessage.swift */; }; + 18920C0F27F233FF00A717B5 /* EmoteRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C0D27F233FF00A717B5 /* EmoteRoomMessage.swift */; }; + 18920C1227F2347600A717B5 /* NoticeRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1027F2347600A717B5 /* NoticeRoomTimelineItem.swift */; }; + 18920C1327F2347600A717B5 /* EmoteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */; }; + 18920C1627F2E3F400A717B5 /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */; }; + 18920C1727F2E3F400A717B5 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */; }; 18ADC7D527E4B20300A8C953 /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */; }; 18ADC7D827E4B63C00A8C953 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 18ADC7D727E4B63C00A8C953 /* MatrixRustSDK */; }; 18ADC7FA27EB02D900A8C953 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18ADC7F927EB02D900A8C953 /* AttributedStringBuilder.swift */; }; @@ -145,6 +151,13 @@ 1850256727B6A135002E6B18 /* ElementX.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = ElementX.entitlements; sourceTree = ""; }; 1850256827B6A135002E6B18 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 1850256A27B6A135002E6B18 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 18920C0B27F2335000A717B5 /* matrix-rust-components-swift */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "matrix-rust-components-swift"; path = "../matrix-rust-components-swift"; sourceTree = ""; }; + 18920C0C27F233FF00A717B5 /* NoticeRoomMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoticeRoomMessage.swift; sourceTree = ""; }; + 18920C0D27F233FF00A717B5 /* EmoteRoomMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomMessage.swift; sourceTree = ""; }; + 18920C1027F2347600A717B5 /* NoticeRoomTimelineItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItem.swift; sourceTree = ""; }; + 18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = ""; }; + 18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = ""; }; + 18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = ""; }; 18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = ""; }; 18ADC7F927EB02D900A8C953 /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = ""; }; 18ADC80427EB1ED100A8C953 /* UIFont+AttributedStringBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+AttributedStringBuilder.m"; sourceTree = ""; }; @@ -274,6 +287,7 @@ 1850251B27B6918C002E6B18 = { isa = PBXGroup; children = ( + 18920C0B27F2335000A717B5 /* matrix-rust-components-swift */, 1850252627B6918C002E6B18 /* ElementX */, 1850253D27B6918D002E6B18 /* ElementXTests */, 1850254727B6918D002E6B18 /* ElementXUITests */, @@ -378,10 +392,12 @@ 18C5744927E1D84000D70937 /* Messages */ = { isa = PBXGroup; children = ( + 18920C0D27F233FF00A717B5 /* EmoteRoomMessage.swift */, + 18C5745127E1D88600D70937 /* ImageRoomMessage.swift */, + 18920C0C27F233FF00A717B5 /* NoticeRoomMessage.swift */, 18C5745527E1DCA800D70937 /* RoomMessageFactory.swift */, 18C5744F27E1D87800D70937 /* RoomMessageProtocol.swift */, 18C5745327E1D88E00D70937 /* TextRoomMessage.swift */, - 18C5745127E1D88600D70937 /* ImageRoomMessage.swift */, ); path = Messages; sourceTree = ""; @@ -414,8 +430,10 @@ 18DF7C3927E4670600291672 /* Items */ = { isa = PBXGroup; children = ( - 18DF7C3A27E4670600291672 /* SeparatorRoomTimelineItem.swift */, + 18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */, 18DF7C3B27E4670600291672 /* ImageRoomTimelineItem.swift */, + 18920C1027F2347600A717B5 /* NoticeRoomTimelineItem.swift */, + 18DF7C3A27E4670600291672 /* SeparatorRoomTimelineItem.swift */, 18DF7C3C27E4670600291672 /* TextRoomTimelineItem.swift */, ); path = Items; @@ -424,12 +442,14 @@ 18DF7C3D27E4670600291672 /* Views */ = { isa = PBXGroup; children = ( - 18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */, + 18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */, 18DF7C4F27E46A7A00291672 /* EventBasedTimelineView.swift */, - 18DF7C4027E4670600291672 /* TextRoomTimelineView.swift */, - 18DF7C3E27E4670600291672 /* ImageRoomTimelineView.swift */, - 18DF7C3F27E4670600291672 /* SeparatorRoomTimelineView.swift */, 18DDB72427EC784E000F1ABF /* FormattedBodyText.swift */, + 18DF7C3E27E4670600291672 /* ImageRoomTimelineView.swift */, + 18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */, + 18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */, + 18DF7C3F27E4670600291672 /* SeparatorRoomTimelineView.swift */, + 18DF7C4027E4670600291672 /* TextRoomTimelineView.swift */, ); path = Views; sourceTree = ""; @@ -960,10 +980,14 @@ 18C5744D27E1D84000D70937 /* RoomProxy.swift in Sources */, 18F2BB0027D25B4000DD1988 /* HomeScreen.swift in Sources */, 18F2BB2827D2647A00DD1988 /* MockRoomTimelineController.swift in Sources */, + 18920C0F27F233FF00A717B5 /* EmoteRoomMessage.swift in Sources */, 18DF7C3127E3608100291672 /* MediaProviderProtocol.swift in Sources */, 18F2BB0127D25B4000DD1988 /* HomeScreenViewModel.swift in Sources */, 18F2BAF027D25B4000DD1988 /* ActivityDismissal.swift in Sources */, 18F2BADD27D25B4000DD1988 /* KeychainController.swift in Sources */, + 18920C1227F2347600A717B5 /* NoticeRoomTimelineItem.swift in Sources */, + 18920C1727F2E3F400A717B5 /* EmoteRoomTimelineView.swift in Sources */, + 18920C0E27F233FF00A717B5 /* NoticeRoomMessage.swift in Sources */, 18F2BAFB27D25B4000DD1988 /* HomeScreenCoordinator.swift in Sources */, 18F2BB0C27D25B4000DD1988 /* RoomScreenCoordinator.swift in Sources */, 18DF7C5027E46A7A00291672 /* EventBasedTimelineView.swift in Sources */, @@ -980,9 +1004,11 @@ 18C5744C27E1D84000D70937 /* RoomProxyProtocol.swift in Sources */, 18C5744E27E1D84000D70937 /* MockRoomProxy.swift in Sources */, 18F2BADC27D25B4000DD1988 /* UserSession.swift in Sources */, + 18920C1627F2E3F400A717B5 /* NoticeRoomTimelineView.swift in Sources */, 18F2BAEF27D25B4000DD1988 /* ActivityRequest.swift in Sources */, 18F2BAEE27D25B4000DD1988 /* Activity.swift in Sources */, 18F2BAEC27D25B4000DD1988 /* ToastActivityPresenter.swift in Sources */, + 18920C1327F2347600A717B5 /* EmoteRoomTimelineItem.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ElementX/Sources/Services/Room/Messages/EmoteRoomMessage.swift b/ElementX/Sources/Services/Room/Messages/EmoteRoomMessage.swift new file mode 100644 index 000000000..f81d00a7b --- /dev/null +++ b/ElementX/Sources/Services/Room/Messages/EmoteRoomMessage.swift @@ -0,0 +1,39 @@ +// +// EmoteRoomMessage.swift +// ElementX +// +// Created by Stefan Ceriu on 16/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import UIKit +import MatrixRustSDK + +struct EmoteRoomMessage: RoomMessageProtocol { + private let message: MatrixRustSDK.EmoteMessage + + init(message: MatrixRustSDK.EmoteMessage) { + self.message = message + } + + var id: String { + message.baseMessage().id() + } + + var body: String { + message.baseMessage().body() + } + + var htmlBody: String? { + message.htmlBody() + } + + var sender: String { + message.baseMessage().sender() + } + + var originServerTs: Date { + Date(timeIntervalSince1970: TimeInterval(message.baseMessage().originServerTs())) + } +} diff --git a/ElementX/Sources/Services/Room/Messages/NoticeRoomMessage.swift b/ElementX/Sources/Services/Room/Messages/NoticeRoomMessage.swift new file mode 100644 index 000000000..98027f5f0 --- /dev/null +++ b/ElementX/Sources/Services/Room/Messages/NoticeRoomMessage.swift @@ -0,0 +1,39 @@ +// +// NoticeRoomMessage.swift +// ElementX +// +// Created by Stefan Ceriu on 16/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import UIKit +import MatrixRustSDK + +struct NoticeRoomMessage: RoomMessageProtocol { + private let message: MatrixRustSDK.NoticeMessage + + init(message: MatrixRustSDK.NoticeMessage) { + self.message = message + } + + var id: String { + message.baseMessage().id() + } + + var body: String { + message.baseMessage().body() + } + + var htmlBody: String? { + message.htmlBody() + } + + var sender: String { + message.baseMessage().sender() + } + + var originServerTs: Date { + Date(timeIntervalSince1970: TimeInterval(message.baseMessage().originServerTs())) + } +} diff --git a/ElementX/Sources/Services/Room/Messages/RoomMessageFactory.swift b/ElementX/Sources/Services/Room/Messages/RoomMessageFactory.swift index 5a95dfc4f..f29304708 100644 --- a/ElementX/Sources/Services/Room/Messages/RoomMessageFactory.swift +++ b/ElementX/Sources/Services/Room/Messages/RoomMessageFactory.swift @@ -11,10 +11,14 @@ import MatrixRustSDK struct RoomMessageFactory { func buildRoomMessageFrom(_ message: AnyMessage) -> RoomMessageProtocol { - if let textMessage = message.text() { + if let textMessage = message.textMessage() { return TextRoomMessage(message: textMessage) - } else if let imageMessage = message.image() { + } else if let imageMessage = message.imageMessage() { return ImageRoomMessage(message: imageMessage) + } else if let noticeMessage = message.noticeMessage() { + return NoticeRoomMessage(message: noticeMessage) + } else if let emoteMessage = message.emoteMessage() { + return EmoteRoomMessage(message: emoteMessage) } else { fatalError("One of these must exist") } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/EmoteRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/EmoteRoomTimelineItem.swift new file mode 100644 index 000000000..04c5edd38 --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/EmoteRoomTimelineItem.swift @@ -0,0 +1,22 @@ +// +// EmoteRoomTimelineItem.swift +// ElementX +// +// Created by Stefan Ceriu on 11/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import UIKit + +struct EmoteRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Equatable { + let id: String + let text: String + var attributedComponents: [AttributedStringBuilderComponent]? + let timestamp: String + let shouldShowSenderDetails: Bool + + let senderId: String + var senderDisplayName: String? + var senderAvatar: UIImage? +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/NoticeRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/NoticeRoomTimelineItem.swift new file mode 100644 index 000000000..c9c4d7919 --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/NoticeRoomTimelineItem.swift @@ -0,0 +1,22 @@ +// +// NoticeRoomTimelineItem.swift +// ElementX +// +// Created by Stefan Ceriu on 11/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import UIKit + +struct NoticeRoomTimelineItem: EventBasedTimelineItemProtocol, Identifiable, Equatable { + let id: String + let text: String + var attributedComponents: [AttributedStringBuilderComponent]? + let timestamp: String + let shouldShowSenderDetails: Bool + + let senderId: String + var senderDisplayName: String? + var senderAvatar: UIImage? +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift index 1ef933437..6569c9692 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift @@ -23,37 +23,88 @@ struct RoomTimelineItemFactory { } func buildTimelineItemFor(_ roomMessage: RoomMessageProtocol, showSenderDetails: Bool) -> RoomTimelineItemProtocol { - let displayName = memberDetailsProvider.displayNameForUserId(roomMessage.sender) let avatarURL = memberDetailsProvider.avatarURLForUserId(roomMessage.sender) let avatarImage = mediaProvider.imageForURL(avatarURL) switch roomMessage { case let message as TextRoomMessage: - - let attributedText = (message.htmlBody != nil ? attributedStringBuilder.fromHTML(message.htmlBody) : attributedStringBuilder.fromPlain(message.body)) - let attributedComponents = attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedText) - - return TextRoomTimelineItem(id: message.id, - text: message.body, - attributedComponents: attributedComponents, - timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), - shouldShowSenderDetails: showSenderDetails, - senderId: message.sender, - senderDisplayName: displayName, - senderAvatar: avatarImage) + return buildTextTimelineItemFromMessage(message, showSenderDetails, displayName, avatarImage) case let message as ImageRoomMessage: - return ImageRoomTimelineItem(id: message.id, - text: message.body, - timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), - shouldShowSenderDetails: showSenderDetails, - senderId: message.sender, - senderDisplayName: displayName, - senderAvatar: avatarImage, - url: message.url, - image: mediaProvider.imageForURL(message.url)) + return buildImageTimelineItemFromMessage(message, showSenderDetails, displayName, avatarImage) + case let message as NoticeRoomMessage: + return buildNoticeTimelineItemFromMessage(message, showSenderDetails, displayName, avatarImage) + case let message as EmoteRoomMessage: + return buildEmoteTimelineItemFromMessage(message, showSenderDetails, displayName, avatarImage) default: fatalError("Unknown room message.") } } + + // MARK: - Private + private func buildTextTimelineItemFromMessage(_ message: TextRoomMessage, + _ showSenderDetails: Bool, + _ displayName: String?, + _ avatarImage: UIImage?) -> RoomTimelineItemProtocol { + let attributedText = (message.htmlBody != nil ? attributedStringBuilder.fromHTML(message.htmlBody) : attributedStringBuilder.fromPlain(message.body)) + let attributedComponents = attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedText) + + return TextRoomTimelineItem(id: message.id, + text: message.body, + attributedComponents: attributedComponents, + timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), + shouldShowSenderDetails: showSenderDetails, + senderId: message.sender, + senderDisplayName: displayName, + senderAvatar: avatarImage) + } + + private func buildImageTimelineItemFromMessage(_ message: ImageRoomMessage, + _ showSenderDetails: Bool, + _ displayName: String?, + _ avatarImage: UIImage?) -> RoomTimelineItemProtocol { + return ImageRoomTimelineItem(id: message.id, + text: message.body, + timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), + shouldShowSenderDetails: showSenderDetails, + senderId: message.sender, + senderDisplayName: displayName, + senderAvatar: avatarImage, + url: message.url, + image: mediaProvider.imageForURL(message.url)) + } + + private func buildNoticeTimelineItemFromMessage(_ message: NoticeRoomMessage, + _ showSenderDetails: Bool, + _ displayName: String?, + _ avatarImage: UIImage?) -> RoomTimelineItemProtocol { + let attributedText = (message.htmlBody != nil ? attributedStringBuilder.fromHTML(message.htmlBody) : attributedStringBuilder.fromPlain(message.body)) + let attributedComponents = attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedText) + + return NoticeRoomTimelineItem(id: message.id, + text: message.body, + attributedComponents: attributedComponents, + timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), + shouldShowSenderDetails: showSenderDetails, + senderId: message.sender, + senderDisplayName: displayName, + senderAvatar: avatarImage) + } + + private func buildEmoteTimelineItemFromMessage(_ message: EmoteRoomMessage, + _ showSenderDetails: Bool, + _ displayName: String?, + _ avatarImage: UIImage?) -> RoomTimelineItemProtocol { + let attributedText = (message.htmlBody != nil ? attributedStringBuilder.fromHTML(message.htmlBody) : attributedStringBuilder.fromPlain(message.body)) + let attributedComponents = attributedStringBuilder.blockquoteCoalescedComponentsFrom(attributedText) + + return EmoteRoomTimelineItem(id: message.id, + text: message.body, + attributedComponents: attributedComponents, + timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), + shouldShowSenderDetails: showSenderDetails, + senderId: message.sender, + senderDisplayName: displayName, + senderAvatar: avatarImage) + } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift index 3029650bc..a51e927b5 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewFactory.swift @@ -17,6 +17,10 @@ struct RoomTimelineViewFactory { return .image(item) case let item as SeparatorRoomTimelineItem: return .separator(item) + case let item as NoticeRoomTimelineItem: + return .notice(item) + case let item as EmoteRoomTimelineItem: + return .emote(item) default: fatalError("Unknown timeline item") } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift index 1e6c095e7..dcc2fea46 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineViewProvider.swift @@ -13,6 +13,8 @@ enum RoomTimelineViewProvider: Identifiable, Equatable { case text(TextRoomTimelineItem) case separator(SeparatorRoomTimelineItem) case image(ImageRoomTimelineItem) + case emote(EmoteRoomTimelineItem) + case notice(NoticeRoomTimelineItem) var id: String { switch self { @@ -22,6 +24,10 @@ enum RoomTimelineViewProvider: Identifiable, Equatable { return item.id case .image(let item): return item.id + case .emote(let item): + return item.id + case .notice(let item): + return item.id } } } @@ -35,6 +41,10 @@ extension RoomTimelineViewProvider: View { SeparatorRoomTimelineView(timelineItem: item) case .image(let item): ImageRoomTimelineView(timelineItem: item) + case .emote(let item): + EmoteRoomTimelineView(timelineItem: item) + case .notice(let item): + NoticeRoomTimelineView(timelineItem: item) } } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Views/EmoteRoomTimelineView.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Views/EmoteRoomTimelineView.swift new file mode 100644 index 000000000..74788c788 --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Views/EmoteRoomTimelineView.swift @@ -0,0 +1,50 @@ +// +// EmoteRoomTimelineView.swift +// ElementX +// +// Created by Stefan Ceriu on 11/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import SwiftUI + +struct EmoteRoomTimelineView: View { + let timelineItem: EmoteRoomTimelineItem + + var body: some View { + VStack(alignment: .leading) { + EventBasedTimelineView(timelineItem: timelineItem) + HStack(alignment: .top) { + Image(systemName: "face.dashed").padding(.top, 1.0) + if let attributedComponents = timelineItem.attributedComponents { + FormattedBodyText(attributedComponents: attributedComponents) + } else { + Text(timelineItem.text) + } + } + } + .id(timelineItem.id) + } +} + +struct EmoteRoomTimelineView_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 20.0) { + let timelineItem = EmoteRoomTimelineItem(id: UUID().uuidString, + text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.", + timestamp: "Now", + shouldShowSenderDetails: true, + senderId: "Bob") + EmoteRoomTimelineView(timelineItem: timelineItem) + + let timelineItem = EmoteRoomTimelineItem(id: UUID().uuidString, + text: "Some other text", + timestamp: "Later", + shouldShowSenderDetails: true, + senderId: "Anne") + EmoteRoomTimelineView(timelineItem: timelineItem) + } + .padding() + } +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Views/NoticeRoomTimelineView.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Views/NoticeRoomTimelineView.swift new file mode 100644 index 000000000..2865d9400 --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Views/NoticeRoomTimelineView.swift @@ -0,0 +1,50 @@ +// +// NoticeRoomTimelineView.swift +// ElementX +// +// Created by Stefan Ceriu on 11/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation +import SwiftUI + +struct NoticeRoomTimelineView: View { + let timelineItem: NoticeRoomTimelineItem + + var body: some View { + VStack(alignment: .leading) { + EventBasedTimelineView(timelineItem: timelineItem) + HStack(alignment: .top) { + Image(systemName: "exclamationmark.bubble").padding(.top, 2.0) + if let attributedComponents = timelineItem.attributedComponents { + FormattedBodyText(attributedComponents: attributedComponents) + } else { + Text(timelineItem.text) + } + } + } + .id(timelineItem.id) + } +} + +struct NoticeRoomTimelineView_Previews: PreviewProvider { + static var previews: some View { + VStack(spacing: 20.0) { + let timelineItem = NoticeRoomTimelineItem(id: UUID().uuidString, + text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.", + timestamp: "Now", + shouldShowSenderDetails: true, + senderId: "Bob") + NoticeRoomTimelineView(timelineItem: timelineItem) + + let timelineItem = NoticeRoomTimelineItem(id: UUID().uuidString, + text: "Some other text", + timestamp: "Later", + shouldShowSenderDetails: true, + senderId: "Anne") + NoticeRoomTimelineView(timelineItem: timelineItem) + } + .padding() + } +}