mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
Refactor theTimelineItemIdentifier handling; stop relying on optional EventOrTransactionIds and be explicit when setting composer modes from the draft service.
This commit is contained in:
@@ -611,6 +611,7 @@
|
|||||||
86F9D3028A1F4AE819D75560 /* RoomChangePermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D879FC4E881E748BB9B34DC /* RoomChangePermissionsScreenCoordinator.swift */; };
|
86F9D3028A1F4AE819D75560 /* RoomChangePermissionsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D879FC4E881E748BB9B34DC /* RoomChangePermissionsScreenCoordinator.swift */; };
|
||||||
872A6457DF573AF8CEAE927A /* LoginHomeserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9349F590E35CE514A71E6764 /* LoginHomeserver.swift */; };
|
872A6457DF573AF8CEAE927A /* LoginHomeserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9349F590E35CE514A71E6764 /* LoginHomeserver.swift */; };
|
||||||
874FEFB9D4A4AF447E0E086E /* AuthenticationStartScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F7CCC4A9D1927223F559D5 /* AuthenticationStartScreenViewModelProtocol.swift */; };
|
874FEFB9D4A4AF447E0E086E /* AuthenticationStartScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F7CCC4A9D1927223F559D5 /* AuthenticationStartScreenViewModelProtocol.swift */; };
|
||||||
|
877D3CE8680536DB430DE6A2 /* TimelineItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E48C91C8BE55CAE1A3DBC3BC /* TimelineItemIdentifier.swift */; };
|
||||||
878070573C7BF19E735707B4 /* RoomTimelineItemProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DE8D25D6A91030175D52A20 /* RoomTimelineItemProperties.swift */; };
|
878070573C7BF19E735707B4 /* RoomTimelineItemProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DE8D25D6A91030175D52A20 /* RoomTimelineItemProperties.swift */; };
|
||||||
87B4E59A4467F8EC75F82372 /* VoiceMessageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B70A50C41C5871B4DB905E7E /* VoiceMessageRoomTimelineView.swift */; };
|
87B4E59A4467F8EC75F82372 /* VoiceMessageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B70A50C41C5871B4DB905E7E /* VoiceMessageRoomTimelineView.swift */; };
|
||||||
87CEA3E07B602705BC2D2A20 /* ClientBuilderHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0CD1CAFD3F8B057F9AEA5 /* ClientBuilderHook.swift */; };
|
87CEA3E07B602705BC2D2A20 /* ClientBuilderHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC0CD1CAFD3F8B057F9AEA5 /* ClientBuilderHook.swift */; };
|
||||||
@@ -2189,6 +2190,7 @@
|
|||||||
E44E35AA87F49503E7B3BF6E /* AudioConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioConverter.swift; sourceTree = "<group>"; };
|
E44E35AA87F49503E7B3BF6E /* AudioConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioConverter.swift; sourceTree = "<group>"; };
|
||||||
E45EBAFF1A83538D54ABDF92 /* ServerSelectionScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModelTests.swift; sourceTree = "<group>"; };
|
E45EBAFF1A83538D54ABDF92 /* ServerSelectionScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionScreenViewModelTests.swift; sourceTree = "<group>"; };
|
||||||
E461B3C8BBBFCA400B268D14 /* AppRouteURLParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteURLParserTests.swift; sourceTree = "<group>"; };
|
E461B3C8BBBFCA400B268D14 /* AppRouteURLParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouteURLParserTests.swift; sourceTree = "<group>"; };
|
||||||
|
E48C91C8BE55CAE1A3DBC3BC /* TimelineItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemIdentifier.swift; sourceTree = "<group>"; };
|
||||||
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; };
|
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = "<group>"; };
|
||||||
E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = "<group>"; };
|
E53BFB7E4F329621C844E8C3 /* AnalyticsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsPromptScreen.swift; sourceTree = "<group>"; };
|
||||||
E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; };
|
E55B5EA766E89FF1F87C3ACB /* RoomNotificationSettingsProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationSettingsProxyProtocol.swift; sourceTree = "<group>"; };
|
||||||
@@ -5473,6 +5475,7 @@
|
|||||||
0DF5CBAF69BDF5DF31C661E1 /* IntentionalMentions.swift */,
|
0DF5CBAF69BDF5DF31C661E1 /* IntentionalMentions.swift */,
|
||||||
66F2402D738694F98729A441 /* RoomTimelineProvider.swift */,
|
66F2402D738694F98729A441 /* RoomTimelineProvider.swift */,
|
||||||
095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */,
|
095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */,
|
||||||
|
E48C91C8BE55CAE1A3DBC3BC /* TimelineItemIdentifier.swift */,
|
||||||
2D505843AB66822EB91F0DF0 /* TimelineItemProxy.swift */,
|
2D505843AB66822EB91F0DF0 /* TimelineItemProxy.swift */,
|
||||||
55AEEF8142DF1B59DB40FB93 /* TimelineItemSender.swift */,
|
55AEEF8142DF1B59DB40FB93 /* TimelineItemSender.swift */,
|
||||||
F9E543072DE58E751F028998 /* TimelineProxy.swift */,
|
F9E543072DE58E751F028998 /* TimelineProxy.swift */,
|
||||||
@@ -6931,6 +6934,7 @@
|
|||||||
E6FA87F773424B27614B23E9 /* TimelineItemAccessibilityModifier.swift in Sources */,
|
E6FA87F773424B27614B23E9 /* TimelineItemAccessibilityModifier.swift in Sources */,
|
||||||
79959F8E45C3749997482A7F /* TimelineItemBubbledStylerView.swift in Sources */,
|
79959F8E45C3749997482A7F /* TimelineItemBubbledStylerView.swift in Sources */,
|
||||||
A808DC3F72D15C6C5A52317E /* TimelineItemDebugView.swift in Sources */,
|
A808DC3F72D15C6C5A52317E /* TimelineItemDebugView.swift in Sources */,
|
||||||
|
877D3CE8680536DB430DE6A2 /* TimelineItemIdentifier.swift in Sources */,
|
||||||
C0B97FFEC0083F3A36609E61 /* TimelineItemMacContextMenu.swift in Sources */,
|
C0B97FFEC0083F3A36609E61 /* TimelineItemMacContextMenu.swift in Sources */,
|
||||||
6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */,
|
6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */,
|
||||||
AE07F215EBC2B9CBF17AA54B /* TimelineItemMenuAction.swift in Sources */,
|
AE07F215EBC2B9CBF17AA54B /* TimelineItemMenuAction.swift in Sources */,
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
|||||||
|
|
||||||
switch await roomProxy.timeline.sendMessage(replyText,
|
switch await roomProxy.timeline.sendMessage(replyText,
|
||||||
html: nil,
|
html: nil,
|
||||||
|
inReplyToEventID: nil,
|
||||||
intentionalMentions: .empty) {
|
intentionalMentions: .empty) {
|
||||||
case .success:
|
case .success:
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -13987,8 +13987,8 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
|||||||
var editNewContentCalled: Bool {
|
var editNewContentCalled: Bool {
|
||||||
return editNewContentCallsCount > 0
|
return editNewContentCallsCount > 0
|
||||||
}
|
}
|
||||||
var editNewContentReceivedArguments: (timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation)?
|
var editNewContentReceivedArguments: (eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation)?
|
||||||
var editNewContentReceivedInvocations: [(timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation)] = []
|
var editNewContentReceivedInvocations: [(eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation)] = []
|
||||||
|
|
||||||
var editNewContentUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
var editNewContentUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
||||||
var editNewContentReturnValue: Result<Void, TimelineProxyError>! {
|
var editNewContentReturnValue: Result<Void, TimelineProxyError>! {
|
||||||
@@ -14014,16 +14014,16 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var editNewContentClosure: ((EventTimelineItem, RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>)?
|
var editNewContentClosure: ((EventOrTransactionId, RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>)?
|
||||||
|
|
||||||
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
||||||
editNewContentCallsCount += 1
|
editNewContentCallsCount += 1
|
||||||
editNewContentReceivedArguments = (timelineItem: timelineItem, newContent: newContent)
|
editNewContentReceivedArguments = (eventOrTransactionID: eventOrTransactionID, newContent: newContent)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.editNewContentReceivedInvocations.append((timelineItem: timelineItem, newContent: newContent))
|
self.editNewContentReceivedInvocations.append((eventOrTransactionID: eventOrTransactionID, newContent: newContent))
|
||||||
}
|
}
|
||||||
if let editNewContentClosure = editNewContentClosure {
|
if let editNewContentClosure = editNewContentClosure {
|
||||||
return await editNewContentClosure(timelineItem, newContent)
|
return await editNewContentClosure(eventOrTransactionID, newContent)
|
||||||
} else {
|
} else {
|
||||||
return editNewContentReturnValue
|
return editNewContentReturnValue
|
||||||
}
|
}
|
||||||
@@ -14770,15 +14770,15 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
//MARK: - sendMessage
|
//MARK: - sendMessage
|
||||||
|
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsUnderlyingCallsCount = 0
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingCallsCount = 0
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsCallsCount: Int {
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsCallsCount: Int {
|
||||||
get {
|
get {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
return sendMessageHtmlInReplyToIntentionalMentionsUnderlyingCallsCount
|
return sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingCallsCount
|
||||||
} else {
|
} else {
|
||||||
var returnValue: Int? = nil
|
var returnValue: Int? = nil
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
returnValue = sendMessageHtmlInReplyToIntentionalMentionsUnderlyingCallsCount
|
returnValue = sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingCallsCount
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue!
|
return returnValue!
|
||||||
@@ -14786,29 +14786,29 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
sendMessageHtmlInReplyToIntentionalMentionsUnderlyingCallsCount = newValue
|
sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingCallsCount = newValue
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
sendMessageHtmlInReplyToIntentionalMentionsUnderlyingCallsCount = newValue
|
sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingCallsCount = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsCalled: Bool {
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsCalled: Bool {
|
||||||
return sendMessageHtmlInReplyToIntentionalMentionsCallsCount > 0
|
return sendMessageHtmlInReplyToEventIDIntentionalMentionsCallsCount > 0
|
||||||
}
|
}
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsReceivedArguments: (message: String, html: String?, eventID: String?, intentionalMentions: IntentionalMentions)?
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsReceivedArguments: (message: String, html: String?, inReplyToEventID: String?, intentionalMentions: IntentionalMentions)?
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsReceivedInvocations: [(message: String, html: String?, eventID: String?, intentionalMentions: IntentionalMentions)] = []
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsReceivedInvocations: [(message: String, html: String?, inReplyToEventID: String?, intentionalMentions: IntentionalMentions)] = []
|
||||||
|
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsReturnValue: Result<Void, TimelineProxyError>! {
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsReturnValue: Result<Void, TimelineProxyError>! {
|
||||||
get {
|
get {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
return sendMessageHtmlInReplyToIntentionalMentionsUnderlyingReturnValue
|
return sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingReturnValue
|
||||||
} else {
|
} else {
|
||||||
var returnValue: Result<Void, TimelineProxyError>? = nil
|
var returnValue: Result<Void, TimelineProxyError>? = nil
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
returnValue = sendMessageHtmlInReplyToIntentionalMentionsUnderlyingReturnValue
|
returnValue = sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnValue!
|
return returnValue!
|
||||||
@@ -14816,26 +14816,26 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if Thread.isMainThread {
|
if Thread.isMainThread {
|
||||||
sendMessageHtmlInReplyToIntentionalMentionsUnderlyingReturnValue = newValue
|
sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingReturnValue = newValue
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.sync {
|
||||||
sendMessageHtmlInReplyToIntentionalMentionsUnderlyingReturnValue = newValue
|
sendMessageHtmlInReplyToEventIDIntentionalMentionsUnderlyingReturnValue = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sendMessageHtmlInReplyToIntentionalMentionsClosure: ((String, String?, String?, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
|
var sendMessageHtmlInReplyToEventIDIntentionalMentionsClosure: ((String, String?, String?, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
|
||||||
|
|
||||||
func sendMessage(_ message: String, html: String?, inReplyTo eventID: String?, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
func sendMessage(_ message: String, html: String?, inReplyToEventID: String?, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||||
sendMessageHtmlInReplyToIntentionalMentionsCallsCount += 1
|
sendMessageHtmlInReplyToEventIDIntentionalMentionsCallsCount += 1
|
||||||
sendMessageHtmlInReplyToIntentionalMentionsReceivedArguments = (message: message, html: html, eventID: eventID, intentionalMentions: intentionalMentions)
|
sendMessageHtmlInReplyToEventIDIntentionalMentionsReceivedArguments = (message: message, html: html, inReplyToEventID: inReplyToEventID, intentionalMentions: intentionalMentions)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.sendMessageHtmlInReplyToIntentionalMentionsReceivedInvocations.append((message: message, html: html, eventID: eventID, intentionalMentions: intentionalMentions))
|
self.sendMessageHtmlInReplyToEventIDIntentionalMentionsReceivedInvocations.append((message: message, html: html, inReplyToEventID: inReplyToEventID, intentionalMentions: intentionalMentions))
|
||||||
}
|
}
|
||||||
if let sendMessageHtmlInReplyToIntentionalMentionsClosure = sendMessageHtmlInReplyToIntentionalMentionsClosure {
|
if let sendMessageHtmlInReplyToEventIDIntentionalMentionsClosure = sendMessageHtmlInReplyToEventIDIntentionalMentionsClosure {
|
||||||
return await sendMessageHtmlInReplyToIntentionalMentionsClosure(message, html, eventID, intentionalMentions)
|
return await sendMessageHtmlInReplyToEventIDIntentionalMentionsClosure(message, html, inReplyToEventID, intentionalMentions)
|
||||||
} else {
|
} else {
|
||||||
return sendMessageHtmlInReplyToIntentionalMentionsReturnValue
|
return sendMessageHtmlInReplyToEventIDIntentionalMentionsReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//MARK: - toggleReaction
|
//MARK: - toggleReaction
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ extension Poll.Option {
|
|||||||
|
|
||||||
extension PollRoomTimelineItem {
|
extension PollRoomTimelineItem {
|
||||||
static func mock(poll: Poll, isOutgoing: Bool = true, isEditable: Bool = false) -> Self {
|
static func mock(poll: Poll, isOutgoing: Bool = true, isEditable: Bool = false) -> Self {
|
||||||
.init(id: .random,
|
.init(id: .randomEvent,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
body: "poll",
|
body: "poll",
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ private struct MessageForwardingListRow: View {
|
|||||||
struct MessageForwardingScreen_Previews: PreviewProvider, TestablePreview {
|
struct MessageForwardingScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let summaryProvider = RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))
|
let summaryProvider = RoomSummaryProviderMock(.init(state: .loaded(.mockRooms)))
|
||||||
let viewModel = MessageForwardingScreenViewModel(forwardingItem: .init(id: .init(uniqueID: ""),
|
let viewModel = MessageForwardingScreenViewModel(forwardingItem: .init(id: .randomEvent,
|
||||||
roomID: "",
|
roomID: "",
|
||||||
content: .init(noPointer: .init())),
|
content: .init(noPointer: .init())),
|
||||||
clientProxy: ClientProxyMock(.init()),
|
clientProxy: ClientProxyMock(.init()),
|
||||||
|
|||||||
+2
-2
@@ -94,7 +94,7 @@ struct ResolveVerifiedUserSendFailureScreen_Previews: PreviewProvider, TestableP
|
|||||||
|
|
||||||
static func makeViewModel(failure: TimelineItemSendFailure.VerifiedUser) -> ResolveVerifiedUserSendFailureScreenViewModel {
|
static func makeViewModel(failure: TimelineItemSendFailure.VerifiedUser) -> ResolveVerifiedUserSendFailureScreenViewModel {
|
||||||
ResolveVerifiedUserSendFailureScreenViewModel(failure: failure,
|
ResolveVerifiedUserSendFailureScreenViewModel(failure: failure,
|
||||||
itemID: .random,
|
itemID: .randomEvent,
|
||||||
roomProxy: JoinedRoomProxyMock(.init()),
|
roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ struct ResolveVerifiedUserSendFailureScreen_Previews: PreviewProvider, TestableP
|
|||||||
|
|
||||||
struct ResolveVerifiedUserSendFailureScreenSheet_Previews: PreviewProvider {
|
struct ResolveVerifiedUserSendFailureScreenSheet_Previews: PreviewProvider {
|
||||||
static let viewModel = ResolveVerifiedUserSendFailureScreenViewModel(failure: .changedIdentity(users: ["@alice:matrix.org"]),
|
static let viewModel = ResolveVerifiedUserSendFailureScreenViewModel(failure: .changedIdentity(users: ["@alice:matrix.org"]),
|
||||||
itemID: .random,
|
itemID: .randomEvent,
|
||||||
roomProxy: JoinedRoomProxyMock(.init()),
|
roomProxy: JoinedRoomProxyMock(.init()),
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Compound
|
import Compound
|
||||||
|
import MatrixRustSDK
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import WysiwygComposer
|
import WysiwygComposer
|
||||||
|
|
||||||
@@ -283,9 +284,14 @@ extension FormatType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum ComposerMode: Equatable {
|
enum ComposerMode: Equatable {
|
||||||
|
enum EditSource {
|
||||||
|
case timeline
|
||||||
|
case draftService
|
||||||
|
}
|
||||||
|
|
||||||
case `default`
|
case `default`
|
||||||
case reply(itemID: TimelineItemIdentifier, replyDetails: TimelineItemReplyDetails, isThread: Bool)
|
case reply(eventID: String, replyDetails: TimelineItemReplyDetails, isThread: Bool)
|
||||||
case edit(originalItemId: TimelineItemIdentifier)
|
case edit(originalEventOrTransactionID: EventOrTransactionId, source: EditSource)
|
||||||
case recordVoiceMessage(state: AudioRecorderState)
|
case recordVoiceMessage(state: AudioRecorderState)
|
||||||
case previewVoiceMessage(state: AudioPlayerState, waveform: WaveformSource, isUploading: Bool)
|
case previewVoiceMessage(state: AudioPlayerState, waveform: WaveformSource, isUploading: Bool)
|
||||||
|
|
||||||
@@ -323,8 +329,8 @@ enum ComposerMode: Equatable {
|
|||||||
|
|
||||||
var replyEventID: String? {
|
var replyEventID: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .reply(let itemID, _, _):
|
case .reply(let eventID, _, _):
|
||||||
return itemID.eventID
|
return eventID
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,9 +258,9 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
|||||||
case .newMessage:
|
case .newMessage:
|
||||||
set(mode: .default)
|
set(mode: .default)
|
||||||
case .edit(let eventID):
|
case .edit(let eventID):
|
||||||
set(mode: .edit(originalItemId: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: eventID))))
|
set(mode: .edit(originalEventOrTransactionID: .eventId(eventId: eventID), source: .draftService))
|
||||||
case .reply(let eventID):
|
case .reply(let eventID):
|
||||||
set(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: eventID)), replyDetails: .loading(eventID: eventID), isThread: false))
|
set(mode: .reply(eventID: eventID, replyDetails: .loading(eventID: eventID), isThread: false))
|
||||||
replyLoadingTask = Task {
|
replyLoadingTask = Task {
|
||||||
let reply = switch await draftService.getReply(eventID: eventID) {
|
let reply = switch await draftService.getReply(eventID: eventID) {
|
||||||
case .success(let reply):
|
case .success(let reply):
|
||||||
@@ -273,7 +273,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
set(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: eventID)), replyDetails: reply.details, isThread: reply.isThreaded))
|
set(mode: .reply(eventID: eventID, replyDetails: reply.details, isThread: reply.isThreaded))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,17 +314,9 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
|||||||
switch state.composerMode {
|
switch state.composerMode {
|
||||||
case .default:
|
case .default:
|
||||||
type = .newMessage
|
type = .newMessage
|
||||||
case .edit(let itemID):
|
case .edit(.eventId(let originalEventID), _):
|
||||||
guard let eventID = itemID.eventID else {
|
type = .edit(eventID: originalEventID)
|
||||||
MXLog.error("The event id for this message is missing")
|
case .reply(let eventID, _, _):
|
||||||
return
|
|
||||||
}
|
|
||||||
type = .edit(eventID: eventID)
|
|
||||||
case .reply(let itemID, _, _):
|
|
||||||
guard let eventID = itemID.eventID else {
|
|
||||||
MXLog.error("The event id for this message is missing")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type = .reply(eventID: eventID)
|
type = .reply(eventID: eventID)
|
||||||
default:
|
default:
|
||||||
if isVolatile {
|
if isVolatile {
|
||||||
|
|||||||
@@ -415,10 +415,10 @@ extension ComposerToolbar {
|
|||||||
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
mentionDisplayHelper: ComposerMentionDisplayHelper.mock,
|
||||||
analyticsService: ServiceLocator.shared.analytics,
|
analyticsService: ServiceLocator.shared.analytics,
|
||||||
composerDraftService: ComposerDraftServiceMock())
|
composerDraftService: ComposerDraftServiceMock())
|
||||||
model.state.composerMode = isLoading ? .reply(itemID: .init(uniqueID: ""),
|
model.state.composerMode = isLoading ? .reply(eventID: UUID().uuidString,
|
||||||
replyDetails: .loading(eventID: ""),
|
replyDetails: .loading(eventID: ""),
|
||||||
isThread: false) :
|
isThread: false) :
|
||||||
.reply(itemID: .init(uniqueID: ""),
|
.reply(eventID: UUID().uuidString,
|
||||||
replyDetails: .loaded(sender: .init(id: "",
|
replyDetails: .loaded(sender: .init(id: "",
|
||||||
displayName: "Test"),
|
displayName: "Test"),
|
||||||
eventID: "", eventContent: .message(.text(.init(body: "Hello World!")))), isThread: false)
|
eventID: "", eventContent: .message(.text(.init(body: "Hello World!")))), isThread: false)
|
||||||
|
|||||||
@@ -275,9 +275,9 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
|||||||
messageComposer()
|
messageComposer()
|
||||||
|
|
||||||
messageComposer(.init(string: "Some message"),
|
messageComposer(.init(string: "Some message"),
|
||||||
mode: .edit(originalItemId: .random))
|
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), source: .timeline))
|
||||||
|
|
||||||
messageComposer(mode: .reply(itemID: .random,
|
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
||||||
replyDetails: .loaded(sender: .init(id: "Kirk"),
|
replyDetails: .loaded(sender: .init(id: "Kirk"),
|
||||||
eventID: "123",
|
eventID: "123",
|
||||||
eventContent: .message(.text(.init(body: "Text: Where the wild things are")))),
|
eventContent: .message(.text(.init(body: "Text: Where the wild things are")))),
|
||||||
@@ -288,7 +288,7 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
|||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
ForEach(replyTypes, id: \.self) { replyDetails in
|
ForEach(replyTypes, id: \.self) { replyDetails in
|
||||||
messageComposer(mode: .reply(itemID: .random,
|
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
||||||
replyDetails: replyDetails, isThread: false))
|
replyDetails: replyDetails, isThread: false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,7 +300,7 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
|||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
ForEach(replyTypes, id: \.self) { replyDetails in
|
ForEach(replyTypes, id: \.self) { replyDetails in
|
||||||
messageComposer(mode: .reply(itemID: .random,
|
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
||||||
replyDetails: replyDetails, isThread: true))
|
replyDetails: replyDetails, isThread: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ class TimelineInteractionHandler {
|
|||||||
let replyInfo = buildReplyInfo(for: eventTimelineItem)
|
let replyInfo = buildReplyInfo(for: eventTimelineItem)
|
||||||
let replyDetails = TimelineItemReplyDetails.loaded(sender: eventTimelineItem.sender, eventID: eventID, eventContent: replyInfo.type)
|
let replyDetails = TimelineItemReplyDetails.loaded(sender: eventTimelineItem.sender, eventID: eventID, eventContent: replyInfo.type)
|
||||||
|
|
||||||
actionsSubject.send(.composer(action: .setMode(mode: .reply(itemID: eventTimelineItem.id, replyDetails: replyDetails, isThread: replyInfo.isThread))))
|
actionsSubject.send(.composer(action: .setMode(mode: .reply(eventID: eventID, replyDetails: replyDetails, isThread: replyInfo.isThread))))
|
||||||
case .forward(let itemID):
|
case .forward(let itemID):
|
||||||
actionsSubject.send(.displayMessageForwarding(itemID: itemID))
|
actionsSubject.send(.displayMessageForwarding(itemID: itemID))
|
||||||
case .viewSource:
|
case .viewSource:
|
||||||
@@ -184,6 +184,11 @@ class TimelineInteractionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func processEditMessageEvent(_ messageTimelineItem: EventBasedMessageTimelineItemProtocol) {
|
private func processEditMessageEvent(_ messageTimelineItem: EventBasedMessageTimelineItemProtocol) {
|
||||||
|
guard case let .event(_, eventOrTransactionID) = messageTimelineItem.id else {
|
||||||
|
MXLog.error("Failed editing message, missing event id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let text: String
|
let text: String
|
||||||
var htmlText: String?
|
var htmlText: String?
|
||||||
switch messageTimelineItem.contentType {
|
switch messageTimelineItem.contentType {
|
||||||
@@ -197,7 +202,7 @@ class TimelineInteractionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Always update the mode first and then the text so that the composer has time to save the text draft
|
// Always update the mode first and then the text so that the composer has time to save the text draft
|
||||||
actionsSubject.send(.composer(action: .setMode(mode: .edit(originalItemId: messageTimelineItem.id))))
|
actionsSubject.send(.composer(action: .setMode(mode: .edit(originalEventOrTransactionID: eventOrTransactionID, source: .timeline))))
|
||||||
actionsSubject.send(.composer(action: .setText(plainText: text, htmlText: htmlText)))
|
actionsSubject.send(.composer(action: .setText(plainText: text, htmlText: htmlText)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -593,13 +593,14 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
actionsSubject.send(.composer(action: .clear))
|
actionsSubject.send(.composer(action: .clear))
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .reply(let itemId, _, _):
|
case .reply(let eventID, _, _):
|
||||||
await timelineController.sendMessage(message,
|
await timelineController.sendMessage(message,
|
||||||
html: html,
|
html: html,
|
||||||
inReplyTo: itemId,
|
inReplyToEventID: eventID,
|
||||||
intentionalMentions: intentionalMentions)
|
intentionalMentions: intentionalMentions)
|
||||||
case .edit(let originalItemId):
|
case .edit(let originalEventOrTransactionID, let source):
|
||||||
await timelineController.edit(originalItemId,
|
await timelineController.edit(originalEventOrTransactionID,
|
||||||
|
useTimeline: source == .timeline,
|
||||||
message: message,
|
message: message,
|
||||||
html: html,
|
html: html,
|
||||||
intentionalMentions: intentionalMentions)
|
intentionalMentions: intentionalMentions)
|
||||||
@@ -610,6 +611,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
case .none:
|
case .none:
|
||||||
await timelineController.sendMessage(message,
|
await timelineController.sendMessage(message,
|
||||||
html: html,
|
html: html,
|
||||||
|
inReplyToEventID: nil,
|
||||||
intentionalMentions: intentionalMentions)
|
intentionalMentions: intentionalMentions)
|
||||||
}
|
}
|
||||||
case .recordVoiceMessage, .previewVoiceMessage:
|
case .recordVoiceMessage, .previewVoiceMessage:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ struct SwipeToReplyView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SwipeToReplyView_Previews: PreviewProvider, TestablePreview {
|
struct SwipeToReplyView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let timelineItem = TextRoomTimelineItem(id: .init(uniqueID: ""),
|
static let timelineItem = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
static var replies: some View {
|
static var replies: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -411,7 +411,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
eventContent: .message(.text(.init(body: "Short"))))),
|
eventContent: .message(.text(.init(body: "Short"))))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -443,7 +443,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
static var encryptionAuthenticity: some View {
|
static var encryptionAuthenticity: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -454,7 +454,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unsignedDevice(color: .red))),
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unsignedDevice(color: .red))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -466,7 +466,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
encryptionAuthenticity: .unsignedDevice(color: .red))),
|
encryptionAuthenticity: .unsignedDevice(color: .red))),
|
||||||
groupStyle: .single))
|
groupStyle: .single))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -477,7 +477,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unknownDevice(color: .red))),
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .unknownDevice(color: .red))),
|
||||||
groupStyle: .first))
|
groupStyle: .first))
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(uniqueID: ""),
|
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -488,7 +488,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))),
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))),
|
||||||
groupStyle: .last))
|
groupStyle: .last))
|
||||||
|
|
||||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
|
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -501,7 +501,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
|
|
||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))))
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))))
|
||||||
|
|
||||||
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(uniqueID: ""),
|
VoiceMessageRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: "10:42",
|
timestamp: "10:42",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -514,7 +514,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
|
|||||||
source: nil,
|
source: nil,
|
||||||
contentType: nil),
|
contentType: nil),
|
||||||
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))),
|
properties: RoomTimelineItemProperties(encryptionAuthenticity: .notGuaranteed(color: .gray))),
|
||||||
playerState: AudioPlayerState(id: .timelineItemIdentifier(.random),
|
playerState: AudioPlayerState(id: .timelineItemIdentifier(.randomEvent),
|
||||||
title: L10n.commonVoiceMessage,
|
title: L10n.commonVoiceMessage,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
waveform: EstimatedWaveform.mockWaveform))
|
waveform: EstimatedWaveform.mockWaveform))
|
||||||
@@ -616,14 +616,14 @@ private struct MockTimelineContent: View {
|
|||||||
source: nil,
|
source: nil,
|
||||||
contentType: nil),
|
contentType: nil),
|
||||||
replyDetails: replyDetails),
|
replyDetails: replyDetails),
|
||||||
playerState: AudioPlayerState(id: .timelineItemIdentifier(.random),
|
playerState: AudioPlayerState(id: .timelineItemIdentifier(.randomEvent),
|
||||||
title: L10n.commonVoiceMessage,
|
title: L10n.commonVoiceMessage,
|
||||||
duration: 10,
|
duration: 10,
|
||||||
waveform: EstimatedWaveform.mockWaveform))
|
waveform: EstimatedWaveform.mockWaveform))
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeItemIdentifier() -> TimelineItemIdentifier {
|
func makeItemIdentifier() -> TimelineItemIdentifier {
|
||||||
isPinned ? .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "pinned")) : .random
|
isPinned ? .event(uniqueID: "", eventOrTransactionID: .eventId(eventId: "pinned")) : .randomEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
var replyDetails: TimelineItemReplyDetails? {
|
var replyDetails: TimelineItemReplyDetails? {
|
||||||
|
|||||||
@@ -180,22 +180,22 @@ private extension EncryptionAuthenticity {
|
|||||||
struct TimelineItemSendInfoLabel_Previews: PreviewProvider, TestablePreview {
|
struct TimelineItemSendInfoLabel_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .random,
|
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .randomEvent,
|
||||||
localizedString: "09:47 AM",
|
localizedString: "09:47 AM",
|
||||||
layoutType: .horizontal()))
|
layoutType: .horizontal()))
|
||||||
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .random,
|
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .randomEvent,
|
||||||
localizedString: "09:47 AM",
|
localizedString: "09:47 AM",
|
||||||
status: .sendingFailed,
|
status: .sendingFailed,
|
||||||
layoutType: .horizontal()))
|
layoutType: .horizontal()))
|
||||||
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .random,
|
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .randomEvent,
|
||||||
localizedString: "09:47 AM",
|
localizedString: "09:47 AM",
|
||||||
status: .encryptionAuthenticity(.unsignedDevice(color: .red)),
|
status: .encryptionAuthenticity(.unsignedDevice(color: .red)),
|
||||||
layoutType: .horizontal()))
|
layoutType: .horizontal()))
|
||||||
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .random,
|
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .randomEvent,
|
||||||
localizedString: "09:47 AM",
|
localizedString: "09:47 AM",
|
||||||
status: .encryptionAuthenticity(.notGuaranteed(color: .gray)),
|
status: .encryptionAuthenticity(.notGuaranteed(color: .gray)),
|
||||||
layoutType: .horizontal()))
|
layoutType: .horizontal()))
|
||||||
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .random,
|
TimelineItemSendInfoLabel(sendInfo: .init(itemID: .randomEvent,
|
||||||
localizedString: "09:47 AM",
|
localizedString: "09:47 AM",
|
||||||
status: .encryptionAuthenticity(.sentInClear(color: .red)),
|
status: .encryptionAuthenticity(.sentInClear(color: .red)),
|
||||||
layoutType: .horizontal()))
|
layoutType: .horizontal()))
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ struct TimelineStyler<Content: View>: View {
|
|||||||
struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = TimelineViewModel.mock
|
static let viewModel = TimelineViewModel.mock
|
||||||
|
|
||||||
static let base = TextRoomTimelineItem(id: .random,
|
static let base = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -80,7 +80,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static let sendingLast: TextRoomTimelineItem = {
|
static let sendingLast: TextRoomTimelineItem = {
|
||||||
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
|
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
|
||||||
var result = TextRoomTimelineItem(id: .init(uniqueID: id),
|
var result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -100,7 +100,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static let sentLast: TextRoomTimelineItem = {
|
static let sentLast: TextRoomTimelineItem = {
|
||||||
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
|
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
|
||||||
let result = TextRoomTimelineItem(id: .init(uniqueID: id),
|
let result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -111,7 +111,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
return result
|
return result
|
||||||
}()
|
}()
|
||||||
|
|
||||||
static let ltrString = TextRoomTimelineItem(id: .random,
|
static let ltrString = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -119,7 +119,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
sender: .test, content: .init(body: "house!"))
|
sender: .test, content: .init(body: "house!"))
|
||||||
|
|
||||||
static let rtlString = TextRoomTimelineItem(id: .random,
|
static let rtlString = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -127,7 +127,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
sender: .test, content: .init(body: "באמת!"))
|
sender: .test, content: .init(body: "באמת!"))
|
||||||
|
|
||||||
static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: .random,
|
static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -136,7 +136,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
sender: .test,
|
sender: .test,
|
||||||
content: .init(body: "house! -- באמת! -- house!"))
|
content: .init(body: "house! -- באמת! -- house!"))
|
||||||
|
|
||||||
static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: .random,
|
static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -145,7 +145,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
sender: .test,
|
sender: .test,
|
||||||
content: .init(body: "באמת! -- house! -- באמת!"))
|
content: .init(body: "באמת! -- house! -- באמת!"))
|
||||||
|
|
||||||
static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: .random,
|
static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -154,7 +154,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
sender: .test,
|
sender: .test,
|
||||||
content: .init(body: "house! -- באמת!"))
|
content: .init(body: "house! -- באמת!"))
|
||||||
|
|
||||||
static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: .random,
|
static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
@@ -196,20 +196,20 @@ struct TimelineReactionViewPreviewsContainer: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(uniqueID: "1"),
|
itemID: .randomEvent,
|
||||||
reactions: [AggregatedReaction.mockReactionWithLongText,
|
reactions: [AggregatedReaction.mockReactionWithLongText,
|
||||||
AggregatedReaction.mockReactionWithLongTextRTL])
|
AggregatedReaction.mockReactionWithLongTextRTL])
|
||||||
Divider()
|
Divider()
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(uniqueID: "2"),
|
itemID: .randomEvent,
|
||||||
reactions: Array(AggregatedReaction.mockReactions.prefix(3)))
|
reactions: Array(AggregatedReaction.mockReactions.prefix(3)))
|
||||||
Divider()
|
Divider()
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(uniqueID: "3"),
|
itemID: .randomEvent,
|
||||||
reactions: AggregatedReaction.mockReactions)
|
reactions: AggregatedReaction.mockReactions)
|
||||||
Divider()
|
Divider()
|
||||||
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
TimelineReactionsView(context: TimelineViewModel.mock.context,
|
||||||
itemID: .init(uniqueID: "4"),
|
itemID: .randomEvent,
|
||||||
reactions: AggregatedReaction.mockReactions,
|
reactions: AggregatedReaction.mockReactions,
|
||||||
isLayoutRTL: true)
|
isLayoutRTL: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview {
|
|||||||
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: .random,
|
TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ struct AudioRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: .random,
|
AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ struct CallInviteRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
CallInviteRoomTimelineView(timelineItem: .init(id: .random,
|
CallInviteRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
canBeRepliedTo: false,
|
canBeRepliedTo: false,
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ struct CallNotificationRoomTimelineView_Previews: PreviewProvider, TestablePrevi
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
CallNotificationRoomTimelineView(timelineItem: .init(id: .random,
|
CallNotificationRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
canBeRepliedTo: false,
|
canBeRepliedTo: false,
|
||||||
|
|||||||
+2
-2
@@ -52,8 +52,8 @@ struct CollapsibleRoomTimelineView: View {
|
|||||||
|
|
||||||
struct CollapsibleRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct CollapsibleRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let item = CollapsibleTimelineItem(items: [
|
static let item = CollapsibleTimelineItem(items: [
|
||||||
SeparatorRoomTimelineItem(id: .init(uniqueID: "First separator"), text: "This is a separator"),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: "First separator"), text: "This is a separator"),
|
||||||
SeparatorRoomTimelineItem(id: .init(uniqueID: "Second separator"), text: "This is another separator")
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Second separator"), text: "This is another separator")
|
||||||
])
|
])
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ struct EmoteRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static func itemWith(text: String, timestamp: String, senderId: String) -> EmoteRoomTimelineItem {
|
private static func itemWith(text: String, timestamp: String, senderId: String) -> EmoteRoomTimelineItem {
|
||||||
EmoteRoomTimelineItem(id: .random,
|
EmoteRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+2
-2
@@ -77,7 +77,7 @@ struct EncryptedRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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: .random,
|
EncryptedRoomTimelineItem(id: .randomEvent,
|
||||||
body: text,
|
body: text,
|
||||||
encryptionType: .unknown,
|
encryptionType: .unknown,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
@@ -88,7 +88,7 @@ struct EncryptedRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static func expectedItemWith(timestamp: String, isOutgoing: Bool, senderId: String) -> EncryptedRoomTimelineItem {
|
private static func expectedItemWith(timestamp: String, isOutgoing: Bool, senderId: String) -> EncryptedRoomTimelineItem {
|
||||||
EncryptedRoomTimelineItem(id: .random,
|
EncryptedRoomTimelineItem(id: .randomEvent,
|
||||||
body: L10n.commonUnableToDecryptNoAccess,
|
body: L10n.commonUnableToDecryptNoAccess,
|
||||||
encryptionType: .megolmV1AesSha2(sessionID: "foo", cause: .membership),
|
encryptionType: .megolmV1AesSha2(sessionID: "foo", cause: .membership),
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct FileRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
VStack(spacing: 20.0) {
|
VStack(spacing: 20.0) {
|
||||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .random,
|
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -47,7 +47,7 @@ struct FileRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
thumbnailSource: nil,
|
thumbnailSource: nil,
|
||||||
contentType: nil)))
|
contentType: nil)))
|
||||||
|
|
||||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .random,
|
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -59,7 +59,7 @@ struct FileRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
thumbnailSource: nil,
|
thumbnailSource: nil,
|
||||||
contentType: nil)))
|
contentType: nil)))
|
||||||
|
|
||||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .random,
|
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+3
-3
@@ -52,7 +52,7 @@ struct ImageRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
VStack(spacing: 20.0) {
|
VStack(spacing: 20.0) {
|
||||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
|
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -63,7 +63,7 @@ struct ImageRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/jpg"),
|
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/jpg"),
|
||||||
thumbnailSource: nil)))
|
thumbnailSource: nil)))
|
||||||
|
|
||||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
|
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -74,7 +74,7 @@ struct ImageRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"),
|
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"),
|
||||||
thumbnailSource: nil)))
|
thumbnailSource: nil)))
|
||||||
|
|
||||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .random,
|
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+3
-3
@@ -86,7 +86,7 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
static var states: some View {
|
static var states: some View {
|
||||||
LocationRoomTimelineView(timelineItem: .init(id: .random,
|
LocationRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -95,7 +95,7 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
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: .random,
|
LocationRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -104,7 +104,7 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "Bob"),
|
||||||
content: .init(body: "Fallback geo uri description",
|
content: .init(body: "Fallback geo uri description",
|
||||||
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description")))
|
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description")))
|
||||||
LocationRoomTimelineView(timelineItem: .init(id: .random,
|
LocationRoomTimelineView(timelineItem: .init(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ struct NoticeRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static func itemWith(text: String, timestamp: String, senderId: String) -> NoticeRoomTimelineItem {
|
private static func itemWith(text: String, timestamp: String, senderId: String) -> NoticeRoomTimelineItem {
|
||||||
NoticeRoomTimelineItem(id: .random,
|
NoticeRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+5
-5
@@ -29,12 +29,12 @@ struct ReadMarkerRoomTimelineView: View {
|
|||||||
struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = TimelineViewModel.mock
|
static let viewModel = TimelineViewModel.mock
|
||||||
|
|
||||||
static let item = ReadMarkerRoomTimelineItem(id: .init(uniqueID: .init(UUID().uuidString)))
|
static let item = ReadMarkerRoomTimelineItem(id: .randomVirtual)
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .init(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
|
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
|
||||||
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .random,
|
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -45,8 +45,8 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
ReadMarkerRoomTimelineView(timelineItem: item)
|
ReadMarkerRoomTimelineView(timelineItem: item)
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .init(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
|
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
|
||||||
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .random,
|
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ struct RedactedRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static func itemWith(text: String, timestamp: String, senderId: String) -> RedactedRoomTimelineItem {
|
private static func itemWith(text: String, timestamp: String, senderId: String) -> RedactedRoomTimelineItem {
|
||||||
RedactedRoomTimelineItem(id: .random,
|
RedactedRoomTimelineItem(id: .randomEvent,
|
||||||
body: text,
|
body: text,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
|
|||||||
+2
-1
@@ -23,7 +23,8 @@ struct SeparatorRoomTimelineView: View {
|
|||||||
|
|
||||||
struct SeparatorRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct SeparatorRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let item = SeparatorRoomTimelineItem(id: .init(uniqueID: "Separator"), text: "This is a separator")
|
let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Separator"),
|
||||||
|
text: "This is a separator")
|
||||||
SeparatorRoomTimelineView(timelineItem: item)
|
SeparatorRoomTimelineView(timelineItem: item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ struct StateRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
StateRoomTimelineView(timelineItem: item)
|
StateRoomTimelineView(timelineItem: item)
|
||||||
}
|
}
|
||||||
|
|
||||||
static let item = StateRoomTimelineItem(id: .random,
|
static let item = StateRoomTimelineItem(id: .randomVirtual,
|
||||||
body: "Alice joined",
|
body: "Alice joined",
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
|
|||||||
+3
-3
@@ -43,7 +43,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
VStack(spacing: 20.0) {
|
VStack(spacing: 20.0) {
|
||||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .random,
|
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .randomEvent,
|
||||||
body: "Some image",
|
body: "Some image",
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -52,7 +52,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "Bob"),
|
||||||
imageURL: URL.picturesDirectory))
|
imageURL: URL.picturesDirectory))
|
||||||
|
|
||||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .random,
|
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .randomEvent,
|
||||||
body: "Some other image",
|
body: "Some other image",
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -61,7 +61,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "Bob"),
|
||||||
imageURL: URL.picturesDirectory))
|
imageURL: URL.picturesDirectory))
|
||||||
|
|
||||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .random,
|
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .randomEvent,
|
||||||
body: "Blurhashed image",
|
body: "Blurhashed image",
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ struct TextRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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: .random,
|
TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: isOutgoing,
|
isEditable: isOutgoing,
|
||||||
@@ -94,7 +94,7 @@ struct TextRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
let builder = AttributedStringBuilder(cacheKey: "preview", mentionBuilder: MentionBuilder())
|
let builder = AttributedStringBuilder(cacheKey: "preview", mentionBuilder: MentionBuilder())
|
||||||
let attributedString = builder.fromHTML(html)
|
let attributedString = builder.fromHTML(html)
|
||||||
|
|
||||||
return TextRoomTimelineItem(id: .random,
|
return TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: isOutgoing,
|
isOutgoing: isOutgoing,
|
||||||
isEditable: isOutgoing,
|
isEditable: isOutgoing,
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ struct UnsupportedRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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: .random,
|
UnsupportedRoomTimelineItem(id: .randomEvent,
|
||||||
body: text,
|
body: text,
|
||||||
eventType: "Some Event Type",
|
eventType: "Some Event Type",
|
||||||
error: "Something went wrong",
|
error: "Something went wrong",
|
||||||
|
|||||||
+3
-3
@@ -63,7 +63,7 @@ struct VideoRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static var body: some View {
|
static var body: some View {
|
||||||
VStack(spacing: 20.0) {
|
VStack(spacing: 20.0) {
|
||||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .random,
|
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -75,7 +75,7 @@ struct VideoRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
source: nil,
|
source: nil,
|
||||||
thumbnailSource: nil)))
|
thumbnailSource: nil)))
|
||||||
|
|
||||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .random,
|
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -87,7 +87,7 @@ struct VideoRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
source: nil,
|
source: nil,
|
||||||
thumbnailSource: nil)))
|
thumbnailSource: nil)))
|
||||||
|
|
||||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .random,
|
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import Foundation
|
|||||||
enum RoomTimelineItemFixtures {
|
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(uniqueID: "Yesterday"), text: "Yesterday"),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Yesterday"), text: "Yesterday"),
|
||||||
TextRoomTimelineItem(id: .init(uniqueID: ".RoomTimelineItemFixtures.default.0",
|
TextRoomTimelineItem(id: .event(uniqueID: ".RoomTimelineItemFixtures.default.0",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.0")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.0")),
|
||||||
timestamp: "10:10 AM",
|
timestamp: "10:10 AM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -21,7 +21,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
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(uniqueID: "RoomTimelineItemFixtures.default.1",
|
TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.1",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.1")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.1")),
|
||||||
timestamp: "10:11 AM",
|
timestamp: "10:11 AM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -33,7 +33,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
properties: RoomTimelineItemProperties(reactions: [
|
properties: RoomTimelineItemProperties(reactions: [
|
||||||
AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(id: "me", timestamp: Date())])
|
AggregatedReaction(accountOwnerID: "me", key: "🙌", senders: [ReactionSender(id: "me", timestamp: Date())])
|
||||||
])),
|
])),
|
||||||
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.2",
|
TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.2",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.2")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.2")),
|
||||||
timestamp: "10:11 AM",
|
timestamp: "10:11 AM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -52,8 +52,8 @@ enum RoomTimelineItemFixtures {
|
|||||||
ReactionSender(id: "jacob", timestamp: Date())
|
ReactionSender(id: "jacob", timestamp: Date())
|
||||||
])
|
])
|
||||||
])),
|
])),
|
||||||
SeparatorRoomTimelineItem(id: .init(uniqueID: "Today"), text: "Today"),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Today"), text: "Today"),
|
||||||
TextRoomTimelineItem(id: .init(uniqueID: "RoomTimelineItemFixtures.default.3",
|
TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.3",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.3")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.3")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -63,7 +63,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
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(uniqueID: "RoomTimelineItemFixtures.default.4",
|
TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.4",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.4")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.4")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
@@ -72,7 +72,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
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(uniqueID: "RoomTimelineItemFixtures.default.5",
|
TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.5",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.5")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.5")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
@@ -86,7 +86,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(uniqueID: "RoomTimelineItemFixtures.default.6",
|
TextRoomTimelineItem(id: .event(uniqueID: "RoomTimelineItemFixtures.default.6",
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.6")),
|
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.6")),
|
||||||
timestamp: "5 PM",
|
timestamp: "5 PM",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
@@ -242,7 +242,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
|
|
||||||
static var permalinkChunk: [RoomTimelineItemProtocol] {
|
static var permalinkChunk: [RoomTimelineItemProtocol] {
|
||||||
(1...20).map { index in
|
(1...20).map { index in
|
||||||
TextRoomTimelineItem(id: .init(uniqueID: "\(index)", eventOrTransactionID: .eventId(eventId: "$\(index)")),
|
TextRoomTimelineItem(id: .event(uniqueID: "\(index)", eventOrTransactionID: .eventId(eventId: "$\(index)")),
|
||||||
text: "Message ID \(index)",
|
text: "Message ID \(index)",
|
||||||
senderDisplayName: index > 10 ? "Alice" : "Bob")
|
senderDisplayName: index > 10 ? "Alice" : "Bob")
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
|
|
||||||
static var mediaChunk: [RoomTimelineItemProtocol] {
|
static var mediaChunk: [RoomTimelineItemProtocol] {
|
||||||
[
|
[
|
||||||
VideoRoomTimelineItem(id: .random,
|
VideoRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:47 am",
|
timestamp: "10:47 am",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -265,7 +265,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
height: 1080,
|
height: 1080,
|
||||||
aspectRatio: 1.78,
|
aspectRatio: 1.78,
|
||||||
blurhash: "KtI~70X5V?yss9oyrYs:t6")),
|
blurhash: "KtI~70X5V?yss9oyrYs:t6")),
|
||||||
ImageRoomTimelineItem(id: .random,
|
ImageRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "10:47 am",
|
timestamp: "10:47 am",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -285,7 +285,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
|
|
||||||
private extension TextRoomTimelineItem {
|
private extension TextRoomTimelineItem {
|
||||||
init(id: TimelineItemIdentifier? = nil, text: String, senderDisplayName: String) {
|
init(id: TimelineItemIdentifier? = nil, text: String, senderDisplayName: String) {
|
||||||
self.init(id: id ?? .random,
|
self.init(id: id ?? .randomEvent,
|
||||||
timestamp: "10:47 am",
|
timestamp: "10:47 am",
|
||||||
isOutgoing: senderDisplayName == "Alice",
|
isOutgoing: senderDisplayName == "Alice",
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
+3
-2
@@ -81,12 +81,13 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
|
|
||||||
func sendMessage(_ message: String,
|
func sendMessage(_ message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
inReplyTo itemID: TimelineItemIdentifier?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async { }
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async { }
|
func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async { }
|
||||||
|
|
||||||
func edit(_ timelineItemID: TimelineItemIdentifier,
|
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
||||||
|
useTimeline: Bool,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async { }
|
||||||
|
|||||||
+15
-35
@@ -143,22 +143,13 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
|
|
||||||
func sendMessage(_ message: String,
|
func sendMessage(_ message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
inReplyTo itemID: TimelineItemIdentifier?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async {
|
intentionalMentions: IntentionalMentions) async {
|
||||||
var inReplyTo: String?
|
|
||||||
if itemID == nil {
|
|
||||||
MXLog.info("Send message in \(roomID)")
|
MXLog.info("Send message in \(roomID)")
|
||||||
} else if let eventID = itemID?.eventID {
|
|
||||||
inReplyTo = eventID
|
|
||||||
MXLog.info("Send reply in \(roomID)")
|
|
||||||
} else {
|
|
||||||
MXLog.error("Send reply in \(roomID) failed: missing event ID")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch await activeTimeline.sendMessage(message,
|
switch await activeTimeline.sendMessage(message,
|
||||||
html: html,
|
html: html,
|
||||||
inReplyTo: inReplyTo,
|
inReplyToEventID: inReplyToEventID,
|
||||||
intentionalMentions: intentionalMentions) {
|
intentionalMentions: intentionalMentions) {
|
||||||
case .success:
|
case .success:
|
||||||
MXLog.info("Finished sending message")
|
MXLog.info("Finished sending message")
|
||||||
@@ -178,37 +169,31 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func edit(_ timelineItemID: TimelineItemIdentifier,
|
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
||||||
|
useTimeline: Bool,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async {
|
intentionalMentions: IntentionalMentions) async {
|
||||||
MXLog.info("Edit message in \(roomID)")
|
MXLog.info("Edit message in \(roomID)")
|
||||||
MXLog.info("Editing timeline item: \(timelineItemID)")
|
MXLog.info("Editing timeline item: \(eventOrTransactionID)")
|
||||||
|
|
||||||
let editMode: EditMode
|
|
||||||
if !timelineItemID.uniqueID.isEmpty,
|
|
||||||
let timelineItem = liveTimelineProvider.itemProxies.firstEventTimelineItemUsingStableID(timelineItemID) {
|
|
||||||
editMode = .byEvent(timelineItem)
|
|
||||||
} else if let eventID = timelineItemID.eventID {
|
|
||||||
editMode = .byID(eventID)
|
|
||||||
} else {
|
|
||||||
MXLog.error("Unknown timeline item: \(timelineItemID)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let messageContent = activeTimeline.buildMessageContentFor(message,
|
let messageContent = activeTimeline.buildMessageContentFor(message,
|
||||||
html: html,
|
html: html,
|
||||||
intentionalMentions: intentionalMentions.toRustMentions())
|
intentionalMentions: intentionalMentions.toRustMentions())
|
||||||
|
|
||||||
switch editMode {
|
if useTimeline {
|
||||||
case let .byEvent(item):
|
switch await activeTimeline.edit(eventOrTransactionID, newContent: messageContent) {
|
||||||
switch await activeTimeline.edit(item, newContent: messageContent) {
|
|
||||||
case .success:
|
case .success:
|
||||||
MXLog.info("Finished editing message by event")
|
MXLog.info("Finished editing message by event")
|
||||||
case let .failure(error):
|
case let .failure(error):
|
||||||
MXLog.error("Failed editing message by event with error: \(error)")
|
MXLog.error("Failed editing message by event with error: \(error)")
|
||||||
}
|
}
|
||||||
case let .byID(eventID):
|
} else {
|
||||||
|
guard case let .eventId(eventID) = eventOrTransactionID else {
|
||||||
|
MXLog.error("Failed editing message, missing eventID.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch await roomProxy.edit(eventID: eventID, newContent: messageContent) {
|
switch await roomProxy.edit(eventID: eventID, newContent: messageContent) {
|
||||||
case .success:
|
case .success:
|
||||||
MXLog.info("Finished editing message by event ID")
|
MXLog.info("Finished editing message by event ID")
|
||||||
@@ -398,9 +383,9 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
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)
|
||||||
|
|
||||||
return SeparatorRoomTimelineItem(id: .init(uniqueID: dateString), text: dateString)
|
return SeparatorRoomTimelineItem(id: .virtual(uniqueID: uniqueID), text: dateString)
|
||||||
case .readMarker:
|
case .readMarker:
|
||||||
return ReadMarkerRoomTimelineItem(id: .init(uniqueID: uniqueID))
|
return ReadMarkerRoomTimelineItem(id: .virtual(uniqueID: uniqueID))
|
||||||
}
|
}
|
||||||
case .unknown:
|
case .unknown:
|
||||||
return nil
|
return nil
|
||||||
@@ -453,8 +438,3 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum EditMode {
|
|
||||||
case byEvent(EventTimelineItem)
|
|
||||||
case byID(String)
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-13
@@ -48,10 +48,11 @@ protocol RoomTimelineControllerProtocol {
|
|||||||
|
|
||||||
func sendMessage(_ message: String,
|
func sendMessage(_ message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
inReplyTo itemID: TimelineItemIdentifier?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async
|
intentionalMentions: IntentionalMentions) async
|
||||||
|
|
||||||
func edit(_ timelineItemID: TimelineItemIdentifier,
|
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
||||||
|
useTimeline: Bool,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async
|
intentionalMentions: IntentionalMentions) async
|
||||||
@@ -72,14 +73,3 @@ protocol RoomTimelineControllerProtocol {
|
|||||||
|
|
||||||
func eventTimestamp(for itemID: TimelineItemIdentifier) -> Date?
|
func eventTimestamp(for itemID: TimelineItemIdentifier) -> Date?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RoomTimelineControllerProtocol {
|
|
||||||
func sendMessage(_ message: String,
|
|
||||||
html: String?,
|
|
||||||
intentionalMentions: IntentionalMentions) async {
|
|
||||||
await sendMessage(message,
|
|
||||||
html: html,
|
|
||||||
inReplyTo: nil,
|
|
||||||
intentionalMentions: intentionalMentions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2024 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
// Please see LICENSE in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MatrixRustSDK
|
||||||
|
|
||||||
|
/// A timeline item identifier
|
||||||
|
/// - uniqueID: Stable id across state changes of the timeline item, it uniquely identifies an item in a timeline.
|
||||||
|
/// Its value is consistent only per timeline instance, it should **not** be used to identify an item across timeline instances.
|
||||||
|
/// - eventOrTransactionID: Contains the 2 possible identifiers of an event, either it has a remote event id or
|
||||||
|
/// a local transaction id, never both or none.
|
||||||
|
enum TimelineItemIdentifier: Hashable {
|
||||||
|
case event(uniqueID: String, eventOrTransactionID: EventOrTransactionId)
|
||||||
|
case virtual(uniqueID: String)
|
||||||
|
|
||||||
|
var uniqueID: String {
|
||||||
|
switch self {
|
||||||
|
case .event(let uniqueID, _):
|
||||||
|
return uniqueID
|
||||||
|
case .virtual(let uniqueID):
|
||||||
|
return uniqueID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventID: String? {
|
||||||
|
guard case let .event(_, eventOrTransactionID) = self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch eventOrTransactionID {
|
||||||
|
case .eventId(let eventID):
|
||||||
|
return eventID
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var transactionID: String? {
|
||||||
|
guard case let .event(_, eventOrTransactionID) = self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch eventOrTransactionID {
|
||||||
|
case .transactionId(let transactionID):
|
||||||
|
return transactionID
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Mocks
|
||||||
|
|
||||||
|
extension TimelineItemIdentifier {
|
||||||
|
static var randomEvent: Self {
|
||||||
|
.event(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: UUID().uuidString))
|
||||||
|
}
|
||||||
|
|
||||||
|
static var randomVirtual: Self {
|
||||||
|
.virtual(uniqueID: UUID().uuidString)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,40 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import MatrixRustSDK
|
import MatrixRustSDK
|
||||||
|
|
||||||
struct TimelineItemIdentifier: Hashable {
|
|
||||||
/// Stable id across state changes of the timeline item, it uniquely identifies an item in a timeline.
|
|
||||||
/// It's value is consistent only per timeline instance, it should **not** be used to identify an item across timeline instances.
|
|
||||||
let uniqueID: String
|
|
||||||
|
|
||||||
/// Contains the 2 possible identifiers of an event, either it has a remote event id or a local transaction id, never both or none.
|
|
||||||
var eventOrTransactionID: EventOrTransactionId?
|
|
||||||
|
|
||||||
var eventID: String? {
|
|
||||||
switch eventOrTransactionID {
|
|
||||||
case .eventId(let eventId):
|
|
||||||
return eventId
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var transactionID: String? {
|
|
||||||
switch eventOrTransactionID {
|
|
||||||
case .transactionId(let transactionId):
|
|
||||||
return transactionId
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TimelineItemIdentifier {
|
|
||||||
/// Use only for mocks/tests
|
|
||||||
static var random: Self {
|
|
||||||
.init(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: 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)
|
||||||
@@ -108,7 +74,7 @@ class EventTimelineItemProxy {
|
|||||||
init(item: MatrixRustSDK.EventTimelineItem, uniqueID: String) {
|
init(item: MatrixRustSDK.EventTimelineItem, uniqueID: String) {
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
id = TimelineItemIdentifier(uniqueID: uniqueID, eventOrTransactionID: item.eventOrTransactionId)
|
id = .event(uniqueID: uniqueID, eventOrTransactionID: item.eventOrTransactionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var deliveryStatus: TimelineItemDeliveryStatus? = {
|
lazy var deliveryStatus: TimelineItemDeliveryStatus? = {
|
||||||
|
|||||||
+1
-1
@@ -97,7 +97,7 @@ struct VoiceMessageRoomPlaybackView_Previews: PreviewProvider, TestablePreview {
|
|||||||
294, 131, 19, 2, 3, 3, 1, 2, 0, 0,
|
294, 131, 19, 2, 3, 3, 1, 2, 0, 0,
|
||||||
0, 0, 0, 0, 0, 3])
|
0, 0, 0, 0, 0, 3])
|
||||||
|
|
||||||
static var playerState = AudioPlayerState(id: .timelineItemIdentifier(.random),
|
static var playerState = AudioPlayerState(id: .timelineItemIdentifier(.randomEvent),
|
||||||
title: L10n.commonVoiceMessage,
|
title: L10n.commonVoiceMessage,
|
||||||
duration: 10.0,
|
duration: 10.0,
|
||||||
waveform: waveform,
|
waveform: waveform,
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@ struct VoiceMessageRoomTimelineView: View {
|
|||||||
|
|
||||||
struct VoiceMessageRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct VoiceMessageRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = TimelineViewModel.mock
|
static let viewModel = TimelineViewModel.mock
|
||||||
static let timelineItemIdentifier = TimelineItemIdentifier.random
|
static let timelineItemIdentifier = TimelineItemIdentifier.randomEvent
|
||||||
static let voiceRoomTimelineItem = VoiceMessageRoomTimelineItem(id: timelineItemIdentifier,
|
static let voiceRoomTimelineItem = VoiceMessageRoomTimelineItem(id: timelineItemIdentifier,
|
||||||
timestamp: "Now",
|
timestamp: "Now",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
|
|||||||
+1
-1
@@ -22,6 +22,6 @@ struct PaginationIndicatorRoomTimelineItem: DecorationTimelineItemProtocol, Equa
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(position: Position) {
|
init(position: Position) {
|
||||||
id = TimelineItemIdentifier(uniqueID: position.id)
|
id = .virtual(uniqueID: position.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -8,6 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
||||||
let id = TimelineItemIdentifier(uniqueID: UUID().uuidString)
|
let id: TimelineItemIdentifier = .virtual(uniqueID: UUID().uuidString)
|
||||||
let name: String?
|
let name: String?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,17 +164,17 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
|
||||||
do {
|
do {
|
||||||
guard try await timeline.edit(eventOrTransactionId: timelineItem.eventOrTransactionId, newContent: .roomMessage(content: newContent)) == true else {
|
guard try await timeline.edit(eventOrTransactionId: eventOrTransactionID, newContent: .roomMessage(content: newContent)) == true else {
|
||||||
return .failure(.failedEditing)
|
return .failure(.failedEditing)
|
||||||
}
|
}
|
||||||
|
|
||||||
MXLog.info("Finished editing timeline item: \(timelineItem.eventOrTransactionId)")
|
MXLog.info("Finished editing timeline item: \(eventOrTransactionID)")
|
||||||
|
|
||||||
return .success(())
|
return .success(())
|
||||||
} catch {
|
} catch {
|
||||||
MXLog.error("Failed editing timeline item: \(timelineItem.eventOrTransactionId) with error: \(error)")
|
MXLog.error("Failed editing timeline item: \(eventOrTransactionID) with error: \(error)")
|
||||||
return .failure(.sdkError(error))
|
return .failure(.sdkError(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,10 +366,10 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
|
|
||||||
func sendMessage(_ message: String,
|
func sendMessage(_ message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
inReplyTo eventID: String? = nil,
|
inReplyToEventID: String? = nil,
|
||||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||||
if let eventID {
|
if let inReplyToEventID {
|
||||||
MXLog.info("Sending reply to eventID: \(eventID)")
|
MXLog.info("Sending reply to eventID: \(inReplyToEventID)")
|
||||||
} else {
|
} else {
|
||||||
MXLog.info("Sending message")
|
MXLog.info("Sending message")
|
||||||
}
|
}
|
||||||
@@ -379,16 +379,16 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
intentionalMentions: intentionalMentions.toRustMentions())
|
intentionalMentions: intentionalMentions.toRustMentions())
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if let eventID {
|
if let inReplyToEventID {
|
||||||
try await timeline.sendReply(msg: messageContent, eventId: eventID)
|
try await timeline.sendReply(msg: messageContent, eventId: inReplyToEventID)
|
||||||
MXLog.info("Finished sending reply to eventID: \(eventID)")
|
MXLog.info("Finished sending reply to eventID: \(inReplyToEventID)")
|
||||||
} else {
|
} else {
|
||||||
_ = try await timeline.send(msg: messageContent)
|
_ = try await timeline.send(msg: messageContent)
|
||||||
MXLog.info("Finished sending message")
|
MXLog.info("Finished sending message")
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
if let eventID {
|
if let inReplyToEventID {
|
||||||
MXLog.error("Failed sending reply to eventID: \(eventID) with error: \(error)")
|
MXLog.error("Failed sending reply to eventID: \(inReplyToEventID) with error: \(error)")
|
||||||
} else {
|
} else {
|
||||||
MXLog.error("Failed sending message with error: \(error)")
|
MXLog.error("Failed sending message with error: \(error)")
|
||||||
}
|
}
|
||||||
@@ -631,4 +631,16 @@ extension Array where Element == TimelineItemProxy {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func firstEventTimelineItemUsingEventOrTransactionID(_ eventOrTransactionID: EventOrTransactionId) -> EventTimelineItem? {
|
||||||
|
for item in self {
|
||||||
|
if case let .event(eventTimelineItem) = item,
|
||||||
|
case let .event(_, identifier) = eventTimelineItem.id,
|
||||||
|
identifier == eventOrTransactionID {
|
||||||
|
return eventTimelineItem.item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ protocol TimelineProxyProtocol {
|
|||||||
func paginateBackwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError>
|
func paginateBackwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError>
|
||||||
func paginateForwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError>
|
func paginateForwards(requestSize: UInt16) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func edit(_ timelineItem: EventTimelineItem, newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>
|
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
||||||
|
newContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func redact(_ timelineItemID: TimelineItemIdentifier,
|
func redact(_ timelineItemID: TimelineItemIdentifier,
|
||||||
reason: String?) async -> Result<Void, TimelineProxyError>
|
reason: String?) async -> Result<Void, TimelineProxyError>
|
||||||
@@ -89,12 +90,11 @@ protocol TimelineProxyProtocol {
|
|||||||
|
|
||||||
func sendMessage(_ message: String,
|
func sendMessage(_ message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
inReplyTo eventID: String?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
|
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async -> Result<Void, TimelineProxyError>
|
func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
// Polls
|
|
||||||
func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result<Void, TimelineProxyError>
|
func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func editPoll(original eventID: String,
|
func editPoll(original eventID: String,
|
||||||
@@ -112,14 +112,3 @@ protocol TimelineProxyProtocol {
|
|||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation
|
intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TimelineProxyProtocol {
|
|
||||||
func sendMessage(_ message: String,
|
|
||||||
html: String?,
|
|
||||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
|
||||||
await sendMessage(message,
|
|
||||||
html: html,
|
|
||||||
inReplyTo: nil,
|
|
||||||
intentionalMentions: intentionalMentions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class AudioPlayerStateTests: XCTestCase {
|
|||||||
override func setUp() async throws {
|
override func setUp() async throws {
|
||||||
audioPlayerActionsSubject = .init()
|
audioPlayerActionsSubject = .init()
|
||||||
audioPlayerSeekCallsSubject = .init()
|
audioPlayerSeekCallsSubject = .init()
|
||||||
audioPlayerState = AudioPlayerState(id: .timelineItemIdentifier(.random), title: "", duration: Self.audioDuration)
|
audioPlayerState = AudioPlayerState(id: .timelineItemIdentifier(.randomEvent), title: "", duration: Self.audioDuration)
|
||||||
audioPlayerMock = buildAudioPlayerMock()
|
audioPlayerMock = buildAudioPlayerMock()
|
||||||
audioPlayerMock.seekToClosure = { [weak self] progress in
|
audioPlayerMock.seekToClosure = { [weak self] progress in
|
||||||
self?.audioPlayerMock.currentTime = Self.audioDuration * progress
|
self?.audioPlayerMock.currentTime = Self.audioDuration * progress
|
||||||
@@ -162,7 +162,7 @@ class AudioPlayerStateTests: XCTestCase {
|
|||||||
func testHandlingAudioPlayerActionDidFinishLoading() async throws {
|
func testHandlingAudioPlayerActionDidFinishLoading() async throws {
|
||||||
audioPlayerMock.duration = 10.0
|
audioPlayerMock.duration = 10.0
|
||||||
|
|
||||||
audioPlayerState = AudioPlayerState(id: .timelineItemIdentifier(.random), title: "", duration: 0)
|
audioPlayerState = AudioPlayerState(id: .timelineItemIdentifier(.randomEvent), title: "", duration: 0)
|
||||||
audioPlayerState.attachAudioPlayer(audioPlayerMock)
|
audioPlayerState.attachAudioPlayer(audioPlayerMock)
|
||||||
|
|
||||||
let deferred = deferFulfillment(audioPlayerState.$playbackState) { action in
|
let deferred = deferFulfillment(audioPlayerState.$playbackState) { action in
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testComposerFocus() {
|
func testComposerFocus() {
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: TimelineItemIdentifier(uniqueID: "mock"))))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventId(eventId: "mock"), source: .timeline)))
|
||||||
XCTAssertTrue(viewModel.state.bindings.composerFocused)
|
XCTAssertTrue(viewModel.state.bindings.composerFocused)
|
||||||
viewModel.process(timelineAction: .removeFocus)
|
viewModel.process(timelineAction: .removeFocus)
|
||||||
XCTAssertFalse(viewModel.state.bindings.composerFocused)
|
XCTAssertFalse(viewModel.state.bindings.composerFocused)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testComposerMode() {
|
func testComposerMode() {
|
||||||
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(uniqueID: "mock"))
|
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventId(eventId: "mock"), source: .timeline)
|
||||||
viewModel.process(timelineAction: .setMode(mode: mode))
|
viewModel.process(timelineAction: .setMode(mode: mode))
|
||||||
XCTAssertEqual(viewModel.state.composerMode, mode)
|
XCTAssertEqual(viewModel.state.composerMode, mode)
|
||||||
viewModel.process(timelineAction: .clear)
|
viewModel.process(timelineAction: .clear)
|
||||||
@@ -56,7 +56,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testComposerModeIsPublished() {
|
func testComposerModeIsPublished() {
|
||||||
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(uniqueID: "mock"))
|
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventId(eventId: "mock"), source: .timeline)
|
||||||
let expectation = expectation(description: "Composer mode is published")
|
let expectation = expectation(description: "Composer mode is published")
|
||||||
let cancellable = viewModel
|
let cancellable = viewModel
|
||||||
.context
|
.context
|
||||||
@@ -236,7 +236,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID")))))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventId(eventId: "testID"), source: .timeline)))
|
||||||
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
||||||
viewModel.saveDraft()
|
viewModel.saveDraft()
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID")),
|
viewModel.process(timelineAction: .setMode(mode: .reply(eventID: "testID",
|
||||||
replyDetails: .loaded(sender: .init(id: ""),
|
replyDetails: .loaded(sender: .init(id: ""),
|
||||||
eventID: "testID",
|
eventID: "testID",
|
||||||
eventContent: .message(.text(.init(body: "reply text")))),
|
eventContent: .message(.text(.init(body: "reply text")))),
|
||||||
@@ -282,7 +282,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID")),
|
viewModel.process(timelineAction: .setMode(mode: .reply(eventID: "testID",
|
||||||
replyDetails: .loaded(sender: .init(id: ""),
|
replyDetails: .loaded(sender: .init(id: ""),
|
||||||
eventID: "testID",
|
eventID: "testID",
|
||||||
eventContent: .message(.text(.init(body: "reply text")))),
|
eventContent: .message(.text(.init(body: "reply text")))),
|
||||||
@@ -395,7 +395,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
await fulfillment(of: [expectation], timeout: 10)
|
await fulfillment(of: [expectation], timeout: 10)
|
||||||
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .edit(originalItemId: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: "testID"))))
|
XCTAssertEqual(viewModel.state.composerMode, .edit(originalEventOrTransactionID: .eventId(eventId: "testID"), source: .draftService))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world!"))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,13 +429,13 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
await fulfillment(of: [draftExpectation], timeout: 10)
|
await fulfillment(of: [draftExpectation], timeout: 10)
|
||||||
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
||||||
// Testing the loading state first
|
// Testing the loading state first
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: testEventID)),
|
XCTAssertEqual(viewModel.state.composerMode, .reply(eventID: testEventID,
|
||||||
replyDetails: .loading(eventID: testEventID),
|
replyDetails: .loading(eventID: testEventID),
|
||||||
isThread: false))
|
isThread: false))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
||||||
|
|
||||||
await fulfillment(of: [loadReplyExpectation], timeout: 10)
|
await fulfillment(of: [loadReplyExpectation], timeout: 10)
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: testEventID)),
|
XCTAssertEqual(viewModel.state.composerMode, .reply(eventID: testEventID,
|
||||||
replyDetails: loadedReply,
|
replyDetails: loadedReply,
|
||||||
isThread: true))
|
isThread: true))
|
||||||
}
|
}
|
||||||
@@ -469,7 +469,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
await fulfillment(of: [draftExpectation], timeout: 10)
|
await fulfillment(of: [draftExpectation], timeout: 10)
|
||||||
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
|
||||||
// Testing the loading state first
|
// Testing the loading state first
|
||||||
XCTAssertEqual(viewModel.state.composerMode, .reply(itemID: .init(uniqueID: "", eventOrTransactionID: .eventId(eventId: testEventID)),
|
XCTAssertEqual(viewModel.state.composerMode, .reply(eventID: testEventID,
|
||||||
replyDetails: .loading(eventID: testEventID),
|
replyDetails: .loading(eventID: testEventID),
|
||||||
isThread: false))
|
isThread: false))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: text))
|
||||||
@@ -483,7 +483,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
func testSaveVolatileDraftWhenEditing() {
|
func testSaveVolatileDraftWhenEditing() {
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: .random)))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), source: .timeline)))
|
||||||
|
|
||||||
let draft = draftServiceMock.saveVolatileDraftReceivedDraft
|
let draft = draftServiceMock.saveVolatileDraftReceivedDraft
|
||||||
XCTAssertNotNil(draft)
|
XCTAssertNotNil(draft)
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class LoggingTests: XCTestCase {
|
|||||||
func validateTimelineContentIsRedacted() throws {
|
func validateTimelineContentIsRedacted() throws {
|
||||||
// Given timeline items that contain text
|
// Given timeline items that contain text
|
||||||
let textAttributedString = "TextAttributed"
|
let textAttributedString = "TextAttributed"
|
||||||
let textMessage = TextRoomTimelineItem(id: .random,
|
let textMessage = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -125,7 +125,7 @@ class LoggingTests: XCTestCase {
|
|||||||
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: .random,
|
let noticeMessage = NoticeRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -134,7 +134,7 @@ class LoggingTests: XCTestCase {
|
|||||||
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: .random,
|
let emoteMessage = EmoteRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -142,7 +142,7 @@ class LoggingTests: XCTestCase {
|
|||||||
isThreaded: false,
|
isThreaded: false,
|
||||||
sender: .init(id: "sender"),
|
sender: .init(id: "sender"),
|
||||||
content: .init(body: "EmoteString", formattedBody: AttributedString(emoteAttributedString)))
|
content: .init(body: "EmoteString", formattedBody: AttributedString(emoteAttributedString)))
|
||||||
let imageMessage = ImageRoomTimelineItem(id: .init(uniqueID: "myimagemessage"),
|
let imageMessage = ImageRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -153,7 +153,7 @@ class LoggingTests: XCTestCase {
|
|||||||
caption: "ImageString",
|
caption: "ImageString",
|
||||||
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/gif"),
|
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/gif"),
|
||||||
thumbnailSource: nil))
|
thumbnailSource: nil))
|
||||||
let videoMessage = VideoRoomTimelineItem(id: .random,
|
let videoMessage = VideoRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@@ -165,7 +165,7 @@ class LoggingTests: XCTestCase {
|
|||||||
duration: 0,
|
duration: 0,
|
||||||
source: nil,
|
source: nil,
|
||||||
thumbnailSource: nil))
|
thumbnailSource: nil))
|
||||||
let fileMessage = FileRoomTimelineItem(id: .random,
|
let fileMessage = FileRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class MediaPlayerProviderTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPlayerStates() async throws {
|
func testPlayerStates() async throws {
|
||||||
let audioPlayerStateId = AudioPlayerStateIdentifier.timelineItemIdentifier(.random)
|
let audioPlayerStateId = AudioPlayerStateIdentifier.timelineItemIdentifier(.randomEvent)
|
||||||
// By default, there should be no player state
|
// By default, there should be no player state
|
||||||
XCTAssertNil(mediaPlayerProvider.playerState(for: audioPlayerStateId))
|
XCTAssertNil(mediaPlayerProvider.playerState(for: audioPlayerStateId))
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ class MediaPlayerProviderTests: XCTestCase {
|
|||||||
let audioPlayer = AudioPlayerMock()
|
let audioPlayer = AudioPlayerMock()
|
||||||
audioPlayer.actions = PassthroughSubject<AudioPlayerAction, Never>().eraseToAnyPublisher()
|
audioPlayer.actions = PassthroughSubject<AudioPlayerAction, Never>().eraseToAnyPublisher()
|
||||||
|
|
||||||
let audioPlayerStates = Array(repeating: AudioPlayerState(id: .timelineItemIdentifier(.random), title: "", duration: 0), count: 10)
|
let audioPlayerStates = Array(repeating: AudioPlayerState(id: .timelineItemIdentifier(.randomEvent), title: "", duration: 0), count: 10)
|
||||||
for audioPlayerState in audioPlayerStates {
|
for audioPlayerState in audioPlayerStates {
|
||||||
mediaPlayerProvider.register(audioPlayerState: audioPlayerState)
|
mediaPlayerProvider.register(audioPlayerState: audioPlayerState)
|
||||||
audioPlayerState.attachAudioPlayer(audioPlayer)
|
audioPlayerState.attachAudioPlayer(audioPlayer)
|
||||||
@@ -95,7 +95,7 @@ class MediaPlayerProviderTests: XCTestCase {
|
|||||||
let audioPlayer = AudioPlayerMock()
|
let audioPlayer = AudioPlayerMock()
|
||||||
audioPlayer.actions = PassthroughSubject<AudioPlayerAction, Never>().eraseToAnyPublisher()
|
audioPlayer.actions = PassthroughSubject<AudioPlayerAction, Never>().eraseToAnyPublisher()
|
||||||
|
|
||||||
let audioPlayerStates = Array(repeating: AudioPlayerState(id: .timelineItemIdentifier(.random), title: "", duration: 0), count: 10)
|
let audioPlayerStates = Array(repeating: AudioPlayerState(id: .timelineItemIdentifier(.randomEvent), title: "", duration: 0), count: 10)
|
||||||
for audioPlayerState in audioPlayerStates {
|
for audioPlayerState in audioPlayerStates {
|
||||||
mediaPlayerProvider.register(audioPlayerState: audioPlayerState)
|
mediaPlayerProvider.register(audioPlayerState: audioPlayerState)
|
||||||
audioPlayerState.attachAudioPlayer(audioPlayer)
|
audioPlayerState.attachAudioPlayer(audioPlayer)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import XCTest
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class MessageForwardingScreenViewModelTests: XCTestCase {
|
class MessageForwardingScreenViewModelTests: XCTestCase {
|
||||||
let forwardingItem = MessageForwardingItem(id: .init(uniqueID: "t1", eventOrTransactionID: .eventId(eventId: "t1")),
|
let forwardingItem = MessageForwardingItem(id: .event(uniqueID: "t1", eventOrTransactionID: .eventId(eventId: "t1")),
|
||||||
roomID: "1",
|
roomID: "1",
|
||||||
content: .init(noPointer: .init()))
|
content: .init(noPointer: .init()))
|
||||||
var viewModel: MessageForwardingScreenViewModelProtocol!
|
var viewModel: MessageForwardingScreenViewModelProtocol!
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class ResolveVerifiedUserSendFailureScreenViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
private func makeViewModel(with failure: TimelineItemSendFailure.VerifiedUser) -> ResolveVerifiedUserSendFailureScreenViewModel {
|
private func makeViewModel(with failure: TimelineItemSendFailure.VerifiedUser) -> ResolveVerifiedUserSendFailureScreenViewModel {
|
||||||
ResolveVerifiedUserSendFailureScreenViewModel(failure: failure,
|
ResolveVerifiedUserSendFailureScreenViewModel(failure: failure,
|
||||||
itemID: .random,
|
itemID: .randomEvent,
|
||||||
roomProxy: roomProxy,
|
roomProxy: roomProxy,
|
||||||
userIndicatorController: UserIndicatorControllerMock())
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,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: .random,
|
let timelineItem = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -24,7 +24,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
|
|||||||
|
|
||||||
func testTextRoomTimelineItemWhitespaceEndLonger() {
|
func testTextRoomTimelineItemWhitespaceEndLonger() {
|
||||||
let timestamp = "10:00 AM"
|
let timestamp = "10:00 AM"
|
||||||
let timelineItem = TextRoomTimelineItem(id: .random,
|
let timelineItem = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -37,7 +37,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
|
|||||||
|
|
||||||
func testTextRoomTimelineItemWhitespaceEndWithEdit() {
|
func testTextRoomTimelineItemWhitespaceEndWithEdit() {
|
||||||
let timestamp = "Now"
|
let timestamp = "Now"
|
||||||
var timelineItem = TextRoomTimelineItem(id: .random,
|
var timelineItem = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@@ -52,7 +52,7 @@ final class TextBasedRoomTimelineTests: XCTestCase {
|
|||||||
|
|
||||||
func testTextRoomTimelineItemWhitespaceEndWithEditAndAlert() {
|
func testTextRoomTimelineItemWhitespaceEndWithEditAndAlert() {
|
||||||
let timestamp = "Now"
|
let timestamp = "Now"
|
||||||
var timelineItem = TextRoomTimelineItem(id: .random,
|
var timelineItem = TextRoomTimelineItem(id: .randomEvent,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
|
|||||||
@@ -423,7 +423,7 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
private extension TextRoomTimelineItem {
|
private extension TextRoomTimelineItem {
|
||||||
init(text: String, sender: String, addReactions: Bool = false, addReadReceipts: [ReadReceipt] = []) {
|
init(text: String, sender: String, addReactions: Bool = false, addReadReceipts: [ReadReceipt] = []) {
|
||||||
let reactions = addReactions ? [AggregatedReaction(accountOwnerID: "bob", key: "🦄", senders: [ReactionSender(id: sender, timestamp: Date())])] : []
|
let reactions = addReactions ? [AggregatedReaction(accountOwnerID: "bob", key: "🦄", senders: [ReactionSender(id: sender, timestamp: Date())])] : []
|
||||||
self.init(id: .random,
|
self.init(id: .randomEvent,
|
||||||
timestamp: "10:47 am",
|
timestamp: "10:47 am",
|
||||||
isOutgoing: sender == "bob",
|
isOutgoing: sender == "bob",
|
||||||
isEditable: sender == "bob",
|
isEditable: sender == "bob",
|
||||||
@@ -437,13 +437,13 @@ private extension TextRoomTimelineItem {
|
|||||||
|
|
||||||
private extension SeparatorRoomTimelineItem {
|
private extension SeparatorRoomTimelineItem {
|
||||||
init(uniqueID: String) {
|
init(uniqueID: String) {
|
||||||
self.init(id: .init(uniqueID: uniqueID), text: "")
|
self.init(id: .virtual(uniqueID: uniqueID), text: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension TextRoomTimelineItem {
|
private extension TextRoomTimelineItem {
|
||||||
init(eventID: String) {
|
init(eventID: String) {
|
||||||
self.init(id: .init(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: eventID)),
|
self.init(id: .event(uniqueID: UUID().uuidString, eventOrTransactionID: .eventId(eventId: eventID)),
|
||||||
timestamp: "",
|
timestamp: "",
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user