mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Refactor Rust timeline identifiers into our own. (#3731)
* Refactor eventOrTransactionID. * Refactor uniqueID.
This commit is contained in:
parent
54dbb33ad5
commit
bad4a8f9c8
@ -14944,8 +14944,8 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
|
|||||||
var editNewContentCalled: Bool {
|
var editNewContentCalled: Bool {
|
||||||
return editNewContentCallsCount > 0
|
return editNewContentCallsCount > 0
|
||||||
}
|
}
|
||||||
var editNewContentReceivedArguments: (eventOrTransactionID: EventOrTransactionId, newContent: EditedContent)?
|
var editNewContentReceivedArguments: (eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, newContent: EditedContent)?
|
||||||
var editNewContentReceivedInvocations: [(eventOrTransactionID: EventOrTransactionId, newContent: EditedContent)] = []
|
var editNewContentReceivedInvocations: [(eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, newContent: EditedContent)] = []
|
||||||
|
|
||||||
var editNewContentUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
var editNewContentUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
||||||
var editNewContentReturnValue: Result<Void, TimelineProxyError>! {
|
var editNewContentReturnValue: Result<Void, TimelineProxyError>! {
|
||||||
@ -14971,9 +14971,9 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var editNewContentClosure: ((EventOrTransactionId, EditedContent) async -> Result<Void, TimelineProxyError>)?
|
var editNewContentClosure: ((TimelineItemIdentifier.EventOrTransactionID, EditedContent) async -> Result<Void, TimelineProxyError>)?
|
||||||
|
|
||||||
func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: EditedContent) async -> Result<Void, TimelineProxyError> {
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, newContent: EditedContent) async -> Result<Void, TimelineProxyError> {
|
||||||
editNewContentCallsCount += 1
|
editNewContentCallsCount += 1
|
||||||
editNewContentReceivedArguments = (eventOrTransactionID: eventOrTransactionID, newContent: newContent)
|
editNewContentReceivedArguments = (eventOrTransactionID: eventOrTransactionID, newContent: newContent)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
@ -15014,8 +15014,8 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
|
|||||||
var redactReasonCalled: Bool {
|
var redactReasonCalled: Bool {
|
||||||
return redactReasonCallsCount > 0
|
return redactReasonCallsCount > 0
|
||||||
}
|
}
|
||||||
var redactReasonReceivedArguments: (eventOrTransactionID: EventOrTransactionId, reason: String?)?
|
var redactReasonReceivedArguments: (eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, reason: String?)?
|
||||||
var redactReasonReceivedInvocations: [(eventOrTransactionID: EventOrTransactionId, reason: String?)] = []
|
var redactReasonReceivedInvocations: [(eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, reason: String?)] = []
|
||||||
|
|
||||||
var redactReasonUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
var redactReasonUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
||||||
var redactReasonReturnValue: Result<Void, TimelineProxyError>! {
|
var redactReasonReturnValue: Result<Void, TimelineProxyError>! {
|
||||||
@ -15041,9 +15041,9 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var redactReasonClosure: ((EventOrTransactionId, String?) async -> Result<Void, TimelineProxyError>)?
|
var redactReasonClosure: ((TimelineItemIdentifier.EventOrTransactionID, String?) async -> Result<Void, TimelineProxyError>)?
|
||||||
|
|
||||||
func redact(_ eventOrTransactionID: EventOrTransactionId, reason: String?) async -> Result<Void, TimelineProxyError> {
|
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, reason: String?) async -> Result<Void, TimelineProxyError> {
|
||||||
redactReasonCallsCount += 1
|
redactReasonCallsCount += 1
|
||||||
redactReasonReceivedArguments = (eventOrTransactionID: eventOrTransactionID, reason: reason)
|
redactReasonReceivedArguments = (eventOrTransactionID: eventOrTransactionID, reason: reason)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
@ -15824,8 +15824,8 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
|
|||||||
var toggleReactionToCalled: Bool {
|
var toggleReactionToCalled: Bool {
|
||||||
return toggleReactionToCallsCount > 0
|
return toggleReactionToCallsCount > 0
|
||||||
}
|
}
|
||||||
var toggleReactionToReceivedArguments: (reaction: String, eventID: EventOrTransactionId)?
|
var toggleReactionToReceivedArguments: (reaction: String, eventID: TimelineItemIdentifier.EventOrTransactionID)?
|
||||||
var toggleReactionToReceivedInvocations: [(reaction: String, eventID: EventOrTransactionId)] = []
|
var toggleReactionToReceivedInvocations: [(reaction: String, eventID: TimelineItemIdentifier.EventOrTransactionID)] = []
|
||||||
|
|
||||||
var toggleReactionToUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
var toggleReactionToUnderlyingReturnValue: Result<Void, TimelineProxyError>!
|
||||||
var toggleReactionToReturnValue: Result<Void, TimelineProxyError>! {
|
var toggleReactionToReturnValue: Result<Void, TimelineProxyError>! {
|
||||||
@ -15851,9 +15851,9 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var toggleReactionToClosure: ((String, EventOrTransactionId) async -> Result<Void, TimelineProxyError>)?
|
var toggleReactionToClosure: ((String, TimelineItemIdentifier.EventOrTransactionID) async -> Result<Void, TimelineProxyError>)?
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to eventID: EventOrTransactionId) async -> Result<Void, TimelineProxyError> {
|
func toggleReaction(_ reaction: String, to eventID: TimelineItemIdentifier.EventOrTransactionID) async -> Result<Void, TimelineProxyError> {
|
||||||
toggleReactionToCallsCount += 1
|
toggleReactionToCallsCount += 1
|
||||||
toggleReactionToReceivedArguments = (reaction: reaction, eventID: eventID)
|
toggleReactionToReceivedArguments = (reaction: reaction, eventID: eventID)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
@ -15,7 +15,7 @@ enum LoadableImageMediaType: Equatable {
|
|||||||
/// An avatar (can be displayed anywhere within the app).
|
/// An avatar (can be displayed anywhere within the app).
|
||||||
case avatar
|
case avatar
|
||||||
/// An image displayed in the timeline.
|
/// An image displayed in the timeline.
|
||||||
case timelineItem(uniqueID: String)
|
case timelineItem(uniqueID: TimelineItemIdentifier.UniqueID)
|
||||||
/// Any other media (can be displayed anywhere within the app).
|
/// Any other media (can be displayed anywhere within the app).
|
||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
@ -88,7 +88,7 @@ struct LoadableImage<TransformerView: View, PlaceholderView: View>: View {
|
|||||||
switch mediaType {
|
switch mediaType {
|
||||||
case .timelineItem(let uniqueID):
|
case .timelineItem(let uniqueID):
|
||||||
// Consider media for the same item to be the same view
|
// Consider media for the same item to be the same view
|
||||||
uniqueID
|
uniqueID.value
|
||||||
default:
|
default:
|
||||||
// Binds the lifecycle of the LoadableImage to the associated URL.
|
// Binds the lifecycle of the LoadableImage to the associated URL.
|
||||||
// This fixes the problem of the cache returning old values after a change in the URL.
|
// This fixes the problem of the cache returning old values after a change in the URL.
|
||||||
@ -323,33 +323,33 @@ struct LoadableImage_Previews: PreviewProvider, TestablePreview {
|
|||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
LazyVGrid(columns: [.init(.adaptive(minimum: 110, maximum: 110))], spacing: 24) {
|
LazyVGrid(columns: [.init(.adaptive(minimum: 110, maximum: 110))], spacing: 24) {
|
||||||
LoadableImage(url: "mxc://wherever/1234",
|
LoadableImage(url: "mxc://wherever/1234",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
mediaProvider: mediaProvider,
|
mediaProvider: mediaProvider,
|
||||||
placeholder: placeholder)
|
placeholder: placeholder)
|
||||||
.layout(title: "Loaded")
|
.layout(title: "Loaded")
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/2345",
|
LoadableImage(url: "mxc://wherever/2345",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
blurhash: "KpE4oyayR5|GbHb];3j@of",
|
blurhash: "KpE4oyayR5|GbHb];3j@of",
|
||||||
mediaProvider: mediaProvider,
|
mediaProvider: mediaProvider,
|
||||||
placeholder: placeholder)
|
placeholder: placeholder)
|
||||||
.layout(title: "Hidden (blurhash)", hideTimelineMedia: true)
|
.layout(title: "Hidden (blurhash)", hideTimelineMedia: true)
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/3456",
|
LoadableImage(url: "mxc://wherever/3456",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
mediaProvider: mediaProvider,
|
mediaProvider: mediaProvider,
|
||||||
placeholder: placeholder)
|
placeholder: placeholder)
|
||||||
.layout(title: "Hidden (placeholder)", hideTimelineMedia: true)
|
.layout(title: "Hidden (placeholder)", hideTimelineMedia: true)
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/4567",
|
LoadableImage(url: "mxc://wherever/4567",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
||||||
mediaProvider: loadingMediaProvider,
|
mediaProvider: loadingMediaProvider,
|
||||||
placeholder: placeholder)
|
placeholder: placeholder)
|
||||||
.layout(title: "Loading (blurhash)")
|
.layout(title: "Loading (blurhash)")
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/5678",
|
LoadableImage(url: "mxc://wherever/5678",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
mediaProvider: loadingMediaProvider,
|
mediaProvider: loadingMediaProvider,
|
||||||
placeholder: placeholder)
|
placeholder: placeholder)
|
||||||
.layout(title: "Loading (placeholder)")
|
.layout(title: "Loading (placeholder)")
|
||||||
@ -361,7 +361,7 @@ struct LoadableImage_Previews: PreviewProvider, TestablePreview {
|
|||||||
.layout(title: "Loading (avatar)")
|
.layout(title: "Loading (avatar)")
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/345",
|
LoadableImage(url: "mxc://wherever/345",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
||||||
mediaProvider: mediaProvider,
|
mediaProvider: mediaProvider,
|
||||||
transformer: transformer,
|
transformer: transformer,
|
||||||
@ -369,7 +369,7 @@ struct LoadableImage_Previews: PreviewProvider, TestablePreview {
|
|||||||
.layout(title: "Loaded (transformer)")
|
.layout(title: "Loaded (transformer)")
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/345",
|
LoadableImage(url: "mxc://wherever/345",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
||||||
mediaProvider: loadingMediaProvider,
|
mediaProvider: loadingMediaProvider,
|
||||||
transformer: transformer,
|
transformer: transformer,
|
||||||
@ -377,7 +377,7 @@ struct LoadableImage_Previews: PreviewProvider, TestablePreview {
|
|||||||
.layout(title: "Loading (transformer)")
|
.layout(title: "Loading (transformer)")
|
||||||
|
|
||||||
LoadableImage(url: "mxc://wherever/234",
|
LoadableImage(url: "mxc://wherever/234",
|
||||||
mediaType: .timelineItem(uniqueID: "id"),
|
mediaType: .timelineItem(uniqueID: .init("id")),
|
||||||
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
blurhash: "KbLM^j]q$jT|EfR-3rtjXk",
|
||||||
mediaProvider: mediaProvider,
|
mediaProvider: mediaProvider,
|
||||||
transformer: transformer,
|
transformer: transformer,
|
||||||
|
@ -63,7 +63,7 @@ struct TimelineMediaPreviewRedactConfirmationView: View {
|
|||||||
.scaledFrame(size: 40)
|
.scaledFrame(size: 40)
|
||||||
.background {
|
.background {
|
||||||
LoadableImage(mediaSource: mediaSource,
|
LoadableImage(mediaSource: mediaSource,
|
||||||
mediaType: .timelineItem(uniqueID: item.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: item.id.uniqueID),
|
||||||
blurhash: item.blurhash,
|
blurhash: item.blurhash,
|
||||||
mediaProvider: context.mediaProvider) {
|
mediaProvider: context.mediaProvider) {
|
||||||
Color.compound.bgSubtleSecondary
|
Color.compound.bgSubtleSecondary
|
||||||
|
@ -113,7 +113,7 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType
|
|||||||
}
|
}
|
||||||
}.reversed().forEach { item in
|
}.reversed().forEach { item in
|
||||||
if case .separator(let item) = item.type {
|
if case .separator(let item) = item.type {
|
||||||
let group = MediaEventsTimelineGroup(id: item.id.uniqueID.id,
|
let group = MediaEventsTimelineGroup(id: item.id.uniqueID.value,
|
||||||
title: titleForDate(item.timestamp),
|
title: titleForDate(item.timestamp),
|
||||||
items: currentItems)
|
items: currentItems)
|
||||||
if !currentItems.isEmpty {
|
if !currentItems.isEmpty {
|
||||||
|
@ -27,7 +27,7 @@ struct ImageMediaEventsTimelineView: View {
|
|||||||
private var loadableImage: some View {
|
private var loadableImage: some View {
|
||||||
if timelineItem.content.contentType == .gif {
|
if timelineItem.content.contentType == .gif {
|
||||||
LoadableImage(mediaSource: timelineItem.content.imageInfo.source,
|
LoadableImage(mediaSource: timelineItem.content.imageInfo.source,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.content.blurhash,
|
blurhash: timelineItem.content.blurhash,
|
||||||
size: timelineItem.content.imageInfo.size,
|
size: timelineItem.content.imageInfo.size,
|
||||||
mediaProvider: context?.mediaProvider) {
|
mediaProvider: context?.mediaProvider) {
|
||||||
@ -36,7 +36,7 @@ struct ImageMediaEventsTimelineView: View {
|
|||||||
.mediaGalleryTimelineAspectRatio(imageInfo: timelineItem.content.imageInfo)
|
.mediaGalleryTimelineAspectRatio(imageInfo: timelineItem.content.imageInfo)
|
||||||
} else {
|
} else {
|
||||||
LoadableImage(mediaSource: timelineItem.content.thumbnailInfo?.source ?? timelineItem.content.imageInfo.source,
|
LoadableImage(mediaSource: timelineItem.content.thumbnailInfo?.source ?? timelineItem.content.imageInfo.source,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.content.blurhash,
|
blurhash: timelineItem.content.blurhash,
|
||||||
size: timelineItem.content.thumbnailInfo?.size ?? timelineItem.content.imageInfo.size,
|
size: timelineItem.content.thumbnailInfo?.size ?? timelineItem.content.imageInfo.size,
|
||||||
mediaProvider: context?.mediaProvider) {
|
mediaProvider: context?.mediaProvider) {
|
||||||
|
@ -22,10 +22,10 @@ struct SeparatorMediaEventsTimelineView: View {
|
|||||||
|
|
||||||
struct SeparatorMediaEventsTimelineView_Previews: PreviewProvider, TestablePreview {
|
struct SeparatorMediaEventsTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Separator")),
|
let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init("Separator")),
|
||||||
timestamp: .mock)
|
timestamp: .mock)
|
||||||
|
|
||||||
SeparatorMediaEventsTimelineView(group: .init(id: item.id.uniqueID.id,
|
SeparatorMediaEventsTimelineView(group: .init(id: item.id.uniqueID.value,
|
||||||
title: "Group",
|
title: "Group",
|
||||||
items: []))
|
items: []))
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ struct VideoMediaEventsTimelineView: View {
|
|||||||
var thumbnail: some View {
|
var thumbnail: some View {
|
||||||
if let thumbnailSource = timelineItem.content.thumbnailInfo?.source {
|
if let thumbnailSource = timelineItem.content.thumbnailInfo?.source {
|
||||||
LoadableImage(mediaSource: thumbnailSource,
|
LoadableImage(mediaSource: thumbnailSource,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.content.blurhash,
|
blurhash: timelineItem.content.blurhash,
|
||||||
size: timelineItem.content.thumbnailInfo?.size,
|
size: timelineItem.content.thumbnailInfo?.size,
|
||||||
mediaProvider: context?.mediaProvider) {
|
mediaProvider: context?.mediaProvider) {
|
||||||
|
@ -294,7 +294,7 @@ enum ComposerMode: Equatable {
|
|||||||
|
|
||||||
case `default`
|
case `default`
|
||||||
case reply(eventID: String, replyDetails: TimelineItemReplyDetails, isThread: Bool)
|
case reply(eventID: String, replyDetails: TimelineItemReplyDetails, isThread: Bool)
|
||||||
case edit(originalEventOrTransactionID: EventOrTransactionId, type: EditType)
|
case edit(originalEventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, type: EditType)
|
||||||
case recordVoiceMessage(state: AudioRecorderState)
|
case recordVoiceMessage(state: AudioRecorderState)
|
||||||
case previewVoiceMessage(state: AudioPlayerState, waveform: WaveformSource, isUploading: Bool)
|
case previewVoiceMessage(state: AudioPlayerState, waveform: WaveformSource, isUploading: Bool)
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ 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(originalEventOrTransactionID: .eventId(eventId: eventID), type: .default))
|
set(mode: .edit(originalEventOrTransactionID: .eventID(eventID), type: .default))
|
||||||
case .reply(let eventID):
|
case .reply(let eventID):
|
||||||
set(mode: .reply(eventID: eventID, replyDetails: .loading(eventID: eventID), isThread: false))
|
set(mode: .reply(eventID: eventID, replyDetails: .loading(eventID: eventID), isThread: false))
|
||||||
replyLoadingTask = Task {
|
replyLoadingTask = Task {
|
||||||
@ -340,7 +340,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
|||||||
switch state.composerMode {
|
switch state.composerMode {
|
||||||
case .default:
|
case .default:
|
||||||
type = .newMessage
|
type = .newMessage
|
||||||
case .edit(.eventId(let originalEventID), .default):
|
case .edit(.eventID(let originalEventID), .default):
|
||||||
type = .edit(eventID: originalEventID)
|
type = .edit(eventID: originalEventID)
|
||||||
case .reply(let eventID, _, _):
|
case .reply(let eventID, _, _):
|
||||||
type = .reply(eventID: eventID)
|
type = .reply(eventID: eventID)
|
||||||
|
@ -302,7 +302,7 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
|||||||
messageComposer()
|
messageComposer()
|
||||||
|
|
||||||
messageComposer(.init(string: "Some message"),
|
messageComposer(.init(string: "Some message"),
|
||||||
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .default))
|
mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .default))
|
||||||
|
|
||||||
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
||||||
replyDetails: .loaded(sender: .init(id: "Kirk"),
|
replyDetails: .loaded(sender: .init(id: "Kirk"),
|
||||||
@ -313,9 +313,9 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
|||||||
Color.clear.frame(height: 20)
|
Color.clear.frame(height: 20)
|
||||||
|
|
||||||
messageComposer(.init(string: "Some new caption"),
|
messageComposer(.init(string: "Some new caption"),
|
||||||
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .addCaption))
|
mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .addCaption))
|
||||||
messageComposer(.init(string: "Some updated caption"),
|
messageComposer(.init(string: "Some updated caption"),
|
||||||
mode: .edit(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .editCaption))
|
mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .editCaption))
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
|
|
||||||
|
@ -206,9 +206,9 @@ struct TimelineState {
|
|||||||
// These can be removed when we have full swiftUI and moved as @State values in the view
|
// These can be removed when we have full swiftUI and moved as @State values in the view
|
||||||
var scrollToBottomPublisher = PassthroughSubject<Void, Never>()
|
var scrollToBottomPublisher = PassthroughSubject<Void, Never>()
|
||||||
|
|
||||||
var itemsDictionary = OrderedDictionary<TimelineUniqueId, RoomTimelineItemViewState>()
|
var itemsDictionary = OrderedDictionary<TimelineItemIdentifier.UniqueID, RoomTimelineItemViewState>()
|
||||||
|
|
||||||
var uniqueIDs: [TimelineUniqueId] {
|
var uniqueIDs: [TimelineItemIdentifier.UniqueID] {
|
||||||
itemsDictionary.keys.elements
|
itemsDictionary.keys.elements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class TimelineTableViewController: UIViewController {
|
|||||||
private let coordinator: TimelineView.Coordinator
|
private let coordinator: TimelineView.Coordinator
|
||||||
private let tableView = UITableView(frame: .zero, style: .plain)
|
private let tableView = UITableView(frame: .zero, style: .plain)
|
||||||
|
|
||||||
var timelineItemsDictionary = OrderedDictionary<TimelineUniqueId, RoomTimelineItemViewState>() {
|
var timelineItemsDictionary = OrderedDictionary<TimelineItemIdentifier.UniqueID, RoomTimelineItemViewState>() {
|
||||||
didSet {
|
didSet {
|
||||||
guard canApplySnapshot else {
|
guard canApplySnapshot else {
|
||||||
hasPendingItems = true
|
hasPendingItems = true
|
||||||
@ -146,12 +146,12 @@ class TimelineTableViewController: UIViewController {
|
|||||||
|
|
||||||
@Binding private var isScrolledToBottom: Bool
|
@Binding private var isScrolledToBottom: Bool
|
||||||
|
|
||||||
private var timelineItemsIDs: [TimelineUniqueId] {
|
private var timelineItemsIDs: [TimelineItemIdentifier.UniqueID] {
|
||||||
timelineItemsDictionary.keys.elements.reversed()
|
timelineItemsDictionary.keys.elements.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The table's diffable data source.
|
/// The table's diffable data source.
|
||||||
private var dataSource: UITableViewDiffableDataSource<TimelineSection, TimelineUniqueId>?
|
private var dataSource: UITableViewDiffableDataSource<TimelineSection, TimelineItemIdentifier.UniqueID>?
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
/// A publisher used to throttle back pagination requests.
|
/// A publisher used to throttle back pagination requests.
|
||||||
@ -247,7 +247,7 @@ class TimelineTableViewController: UIViewController {
|
|||||||
private func configureDataSource() {
|
private func configureDataSource() {
|
||||||
dataSource = .init(tableView: tableView) { [weak self] tableView, indexPath, id in
|
dataSource = .init(tableView: tableView) { [weak self] tableView, indexPath, id in
|
||||||
switch id {
|
switch id {
|
||||||
case TimelineUniqueId(id: TimelineTypingIndicatorCell.reuseIdentifier):
|
case TimelineItemIdentifier.UniqueID(TimelineTypingIndicatorCell.reuseIdentifier):
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: TimelineTypingIndicatorCell.reuseIdentifier, for: indexPath)
|
let cell = tableView.dequeueReusableCell(withIdentifier: TimelineTypingIndicatorCell.reuseIdentifier, for: indexPath)
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return cell
|
return cell
|
||||||
@ -313,12 +313,12 @@ class TimelineTableViewController: UIViewController {
|
|||||||
private func applySnapshot() {
|
private func applySnapshot() {
|
||||||
guard let dataSource else { return }
|
guard let dataSource else { return }
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, TimelineUniqueId>()
|
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, TimelineItemIdentifier.UniqueID>()
|
||||||
|
|
||||||
// We don't want to display the typing notification in this timeline
|
// We don't want to display the typing notification in this timeline
|
||||||
if coordinator.context.viewState.timelineKind != .pinned {
|
if coordinator.context.viewState.timelineKind != .pinned {
|
||||||
snapshot.appendSections([.typingIndicator])
|
snapshot.appendSections([.typingIndicator])
|
||||||
snapshot.appendItems([TimelineUniqueId(id: TimelineTypingIndicatorCell.reuseIdentifier)])
|
snapshot.appendItems([TimelineItemIdentifier.UniqueID(TimelineTypingIndicatorCell.reuseIdentifier)])
|
||||||
}
|
}
|
||||||
snapshot.appendSections([.main])
|
snapshot.appendSections([.main])
|
||||||
snapshot.appendItems(timelineItemsIDs)
|
snapshot.appendItems(timelineItemsIDs)
|
||||||
@ -517,7 +517,7 @@ extension TimelineTableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the frame of the cell for a particular timeline item.
|
/// Returns the frame of the cell for a particular timeline item.
|
||||||
private func cellFrame(for uniqueID: TimelineUniqueId) -> CGRect? {
|
private func cellFrame(for uniqueID: TimelineItemIdentifier.UniqueID) -> CGRect? {
|
||||||
guard let timelineCell = tableView.visibleCells.first(where: { ($0 as? TimelineItemCell)?.item?.identifier.uniqueID == uniqueID }) else {
|
guard let timelineCell = tableView.visibleCells.first(where: { ($0 as? TimelineItemCell)?.item?.identifier.uniqueID == uniqueID }) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -537,13 +537,13 @@ extension TimelineTableViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension NSDiffableDataSourceSnapshot<TimelineTableViewController.TimelineSection, TimelineUniqueId> {
|
private extension NSDiffableDataSourceSnapshot<TimelineTableViewController.TimelineSection, TimelineItemIdentifier.UniqueID> {
|
||||||
var numberOfMainItems: Int {
|
var numberOfMainItems: Int {
|
||||||
guard sectionIdentifiers.contains(.main) else { return 0 }
|
guard sectionIdentifiers.contains(.main) else { return 0 }
|
||||||
return numberOfItems(inSection: .main)
|
return numberOfItems(inSection: .main)
|
||||||
}
|
}
|
||||||
|
|
||||||
var mainItemIdentifiers: [TimelineUniqueId] {
|
var mainItemIdentifiers: [TimelineItemIdentifier.UniqueID] {
|
||||||
guard sectionIdentifiers.contains(.main) else { return [] }
|
guard sectionIdentifiers.contains(.main) else { return [] }
|
||||||
return itemIdentifiers(inSection: .main)
|
return itemIdentifiers(inSection: .main)
|
||||||
}
|
}
|
||||||
|
@ -658,7 +658,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
|||||||
// MARK: - Timeline Item Building
|
// MARK: - Timeline Item Building
|
||||||
|
|
||||||
private func buildTimelineViews(timelineItems: [RoomTimelineItemProtocol], isSwitchingTimelines: Bool = false) {
|
private func buildTimelineViews(timelineItems: [RoomTimelineItemProtocol], isSwitchingTimelines: Bool = false) {
|
||||||
var timelineItemsDictionary = OrderedDictionary<TimelineUniqueId, RoomTimelineItemViewState>()
|
var timelineItemsDictionary = OrderedDictionary<TimelineItemIdentifier.UniqueID, RoomTimelineItemViewState>()
|
||||||
|
|
||||||
timelineItems.filter { $0 is RedactedRoomTimelineItem }.forEach { timelineItem in
|
timelineItems.filter { $0 is RedactedRoomTimelineItem }.forEach { timelineItem in
|
||||||
// Stops the audio player when a voice message is redacted.
|
// Stops the audio player when a voice message is redacted.
|
||||||
|
@ -613,7 +613,7 @@ private struct MockTimelineContent: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeItemIdentifier() -> TimelineItemIdentifier {
|
func makeItemIdentifier() -> TimelineItemIdentifier {
|
||||||
isPinned ? .event(uniqueID: .init(id: ""), eventOrTransactionID: .eventId(eventId: "pinned")) : .randomEvent
|
isPinned ? .event(uniqueID: .init(""), eventOrTransactionID: .eventID("pinned")) : .randomEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
var replyDetails: TimelineItemReplyDetails? {
|
var replyDetails: TimelineItemReplyDetails? {
|
||||||
|
@ -79,8 +79,8 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
static let sendingLast: TextRoomTimelineItem = {
|
static let sendingLast: TextRoomTimelineItem = {
|
||||||
let id = viewModel.state.timelineState.uniqueIDs.last ?? .init(id: UUID().uuidString)
|
let id = viewModel.state.timelineState.uniqueIDs.last ?? .init(UUID().uuidString)
|
||||||
var result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
|
var result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventID(UUID().uuidString)),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@ -99,8 +99,8 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
static let sentLast: TextRoomTimelineItem = {
|
static let sentLast: TextRoomTimelineItem = {
|
||||||
let id = viewModel.state.timelineState.uniqueIDs.last ?? .init(id: UUID().uuidString)
|
let id = viewModel.state.timelineState.uniqueIDs.last ?? .init(UUID().uuidString)
|
||||||
let result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
|
let result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventID(UUID().uuidString)),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
@ -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: .virtual(uniqueID: .init(id: "First separator")), timestamp: .mock),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init("First separator")), timestamp: .mock),
|
||||||
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Second separator")), timestamp: .mock)
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init("Second separator")), timestamp: .mock)
|
||||||
])
|
])
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
@ -44,7 +44,7 @@ struct ImageRoomTimelineView: View {
|
|||||||
private var loadableImage: some View {
|
private var loadableImage: some View {
|
||||||
if timelineItem.content.contentType == .gif {
|
if timelineItem.content.contentType == .gif {
|
||||||
LoadableImage(mediaSource: timelineItem.content.imageInfo.source,
|
LoadableImage(mediaSource: timelineItem.content.imageInfo.source,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.content.blurhash,
|
blurhash: timelineItem.content.blurhash,
|
||||||
size: timelineItem.content.imageInfo.size,
|
size: timelineItem.content.imageInfo.size,
|
||||||
mediaProvider: context?.mediaProvider) {
|
mediaProvider: context?.mediaProvider) {
|
||||||
@ -53,7 +53,7 @@ struct ImageRoomTimelineView: View {
|
|||||||
.timelineMediaFrame(imageInfo: timelineItem.content.imageInfo)
|
.timelineMediaFrame(imageInfo: timelineItem.content.imageInfo)
|
||||||
} else {
|
} else {
|
||||||
LoadableImage(mediaSource: timelineItem.content.thumbnailInfo?.source ?? timelineItem.content.imageInfo.source,
|
LoadableImage(mediaSource: timelineItem.content.thumbnailInfo?.source ?? timelineItem.content.imageInfo.source,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.content.blurhash,
|
blurhash: timelineItem.content.blurhash,
|
||||||
size: timelineItem.content.thumbnailInfo?.size ?? timelineItem.content.imageInfo.size,
|
size: timelineItem.content.thumbnailInfo?.size ?? timelineItem.content.imageInfo.size,
|
||||||
mediaProvider: context?.mediaProvider) {
|
mediaProvider: context?.mediaProvider) {
|
||||||
|
@ -33,7 +33,7 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
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: .virtual(uniqueID: .init(id: "Separator")), timestamp: .mock)), groupStyle: .single))
|
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init("Separator")), timestamp: .mock)), groupStyle: .single))
|
||||||
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
|
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
@ -45,7 +45,7 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
ReadMarkerRoomTimelineView(timelineItem: item)
|
ReadMarkerRoomTimelineView(timelineItem: item)
|
||||||
|
|
||||||
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init(id: "Separator")), timestamp: .mock)), groupStyle: .single))
|
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init("Separator")), timestamp: .mock)), groupStyle: .single))
|
||||||
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
|
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
|
@ -23,7 +23,7 @@ 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: .virtual(uniqueID: .init(id: "Separator")),
|
let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init("Separator")),
|
||||||
timestamp: .mock)
|
timestamp: .mock)
|
||||||
SeparatorRoomTimelineView(timelineItem: item)
|
SeparatorRoomTimelineView(timelineItem: item)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ struct StickerRoomTimelineView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
TimelineStyler(timelineItem: timelineItem) {
|
TimelineStyler(timelineItem: timelineItem) {
|
||||||
LoadableImage(mediaSource: timelineItem.imageInfo.source,
|
LoadableImage(mediaSource: timelineItem.imageInfo.source,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.blurhash,
|
blurhash: timelineItem.blurhash,
|
||||||
size: timelineItem.imageInfo.size,
|
size: timelineItem.imageInfo.size,
|
||||||
mediaProvider: context?.mediaProvider) {
|
mediaProvider: context?.mediaProvider) {
|
||||||
|
@ -45,7 +45,7 @@ struct VideoRoomTimelineView: View {
|
|||||||
var thumbnail: some View {
|
var thumbnail: some View {
|
||||||
if let thumbnailSource = timelineItem.content.thumbnailInfo?.source {
|
if let thumbnailSource = timelineItem.content.thumbnailInfo?.source {
|
||||||
LoadableImage(mediaSource: thumbnailSource,
|
LoadableImage(mediaSource: thumbnailSource,
|
||||||
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID.id),
|
mediaType: .timelineItem(uniqueID: timelineItem.id.uniqueID),
|
||||||
blurhash: timelineItem.content.blurhash,
|
blurhash: timelineItem.content.blurhash,
|
||||||
size: timelineItem.content.thumbnailInfo?.size,
|
size: timelineItem.content.thumbnailInfo?.size,
|
||||||
mediaProvider: context?.mediaProvider) { imageView in
|
mediaProvider: context?.mediaProvider) { imageView in
|
||||||
|
@ -243,7 +243,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
|||||||
var lastMessageFormattedTimestamp: String?
|
var lastMessageFormattedTimestamp: String?
|
||||||
|
|
||||||
if let latestRoomMessage = roomDetails.latestEvent {
|
if let latestRoomMessage = roomDetails.latestEvent {
|
||||||
let lastMessage = EventTimelineItemProxy(item: latestRoomMessage, uniqueID: .init(id: "0"))
|
let lastMessage = EventTimelineItemProxy(item: latestRoomMessage, uniqueID: .init("0"))
|
||||||
lastMessageFormattedTimestamp = lastMessage.timestamp.formattedMinimal()
|
lastMessageFormattedTimestamp = lastMessage.timestamp.formattedMinimal()
|
||||||
attributedLastMessage = eventStringBuilder.buildAttributedString(for: lastMessage)
|
attributedLastMessage = eventStringBuilder.buildAttributedString(for: lastMessage)
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,9 @@ 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: .virtual(uniqueID: .init(id: "Yesterday")), timestamp: .mock),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init("Yesterday")), timestamp: .mock),
|
||||||
TextRoomTimelineItem(id: .event(uniqueID: .init(id: ".RoomTimelineItemFixtures.default.0"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init(".RoomTimelineItemFixtures.default.0"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.0")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.0")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@ -21,8 +21,8 @@ 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: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.1"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("RoomTimelineItemFixtures.default.1"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.1")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.1")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@ -33,8 +33,8 @@ 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: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.2"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("RoomTimelineItemFixtures.default.2"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.2")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.2")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@ -52,9 +52,9 @@ enum RoomTimelineItemFixtures {
|
|||||||
ReactionSender(id: "jacob", timestamp: Date())
|
ReactionSender(id: "jacob", timestamp: Date())
|
||||||
])
|
])
|
||||||
])),
|
])),
|
||||||
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Today")), timestamp: .mock),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init("Today")), timestamp: .mock),
|
||||||
TextRoomTimelineItem(id: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.3"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("RoomTimelineItemFixtures.default.3"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.3")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.3")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
@ -63,8 +63,8 @@ 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: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.4"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("RoomTimelineItemFixtures.default.4"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.4")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.4")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@ -72,8 +72,8 @@ 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: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.5"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("RoomTimelineItemFixtures.default.5"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.5")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.5")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: true,
|
isOutgoing: true,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
@ -86,8 +86,8 @@ 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: .event(uniqueID: .init(id: "RoomTimelineItemFixtures.default.6"),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("RoomTimelineItemFixtures.default.6"),
|
||||||
eventOrTransactionID: .eventId(eventId: "RoomTimelineItemFixtures.default.6")),
|
eventOrTransactionID: .eventID("RoomTimelineItemFixtures.default.6")),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: 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: .event(uniqueID: .init(id: "\(index)"), eventOrTransactionID: .eventId(eventId: "$\(index)")),
|
TextRoomTimelineItem(id: .event(uniqueID: .init("\(index)"), eventOrTransactionID: .eventID("$\(index)")),
|
||||||
text: "Message ID \(index)",
|
text: "Message ID \(index)",
|
||||||
senderDisplayName: index > 10 ? "Alice" : "Bob")
|
senderDisplayName: index > 10 ? "Alice" : "Bob")
|
||||||
}
|
}
|
||||||
@ -264,7 +264,7 @@ enum RoomTimelineItemFixtures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var separator: SeparatorRoomTimelineItem {
|
static var separator: SeparatorRoomTimelineItem {
|
||||||
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: UUID().uuidString)),
|
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(UUID().uuidString)),
|
||||||
timestamp: .now)
|
timestamp: .now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,22 +104,22 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
inReplyToEventID: String?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async { }
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to eventID: EventOrTransactionId) async { }
|
func toggleReaction(_ reaction: String, to eventID: TimelineItemIdentifier.EventOrTransactionID) async { }
|
||||||
|
|
||||||
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async { }
|
||||||
|
|
||||||
func editCaption(_ eventOrTransactionID: EventOrTransactionId,
|
func editCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async { }
|
||||||
|
|
||||||
func removeCaption(_ eventOrTransactionID: EventOrTransactionId) async { }
|
func removeCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async { }
|
||||||
|
|
||||||
private(set) var redactCalled = false
|
private(set) var redactCalled = false
|
||||||
func redact(_ eventOrTransactionID: EventOrTransactionId) async {
|
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async {
|
||||||
redactCalled = true
|
redactCalled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ class TimelineController: TimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to eventOrTransactionID: EventOrTransactionId) async {
|
func toggleReaction(_ reaction: String, to eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async {
|
||||||
MXLog.info("Toggle reaction \(reaction) to \(eventOrTransactionID)")
|
MXLog.info("Toggle reaction \(reaction) to \(eventOrTransactionID)")
|
||||||
|
|
||||||
switch await activeTimeline.toggleReaction(reaction, to: eventOrTransactionID) {
|
switch await activeTimeline.toggleReaction(reaction, to: eventOrTransactionID) {
|
||||||
@ -232,7 +232,7 @@ class TimelineController: TimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async {
|
intentionalMentions: IntentionalMentions) async {
|
||||||
@ -251,7 +251,7 @@ class TimelineController: TimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func editCaption(_ eventOrTransactionID: EventOrTransactionId,
|
func editCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async {
|
intentionalMentions: IntentionalMentions) async {
|
||||||
@ -269,7 +269,7 @@ class TimelineController: TimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeCaption(_ eventOrTransactionID: EventOrTransactionId) async {
|
func removeCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async {
|
||||||
// Set a `nil` caption to remove it from the event.
|
// Set a `nil` caption to remove it from the event.
|
||||||
let newContent = createCaptionEdit(caption: nil, formattedCaption: nil, mentions: nil)
|
let newContent = createCaptionEdit(caption: nil, formattedCaption: nil, mentions: nil)
|
||||||
switch await activeTimeline.edit(eventOrTransactionID, newContent: newContent) {
|
switch await activeTimeline.edit(eventOrTransactionID, newContent: newContent) {
|
||||||
@ -280,7 +280,7 @@ class TimelineController: TimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func redact(_ eventOrTransactionID: EventOrTransactionId) async {
|
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async {
|
||||||
MXLog.info("Send redaction in \(roomID)")
|
MXLog.info("Send redaction in \(roomID)")
|
||||||
|
|
||||||
switch await activeTimeline.redact(eventOrTransactionID, reason: nil) {
|
switch await activeTimeline.redact(eventOrTransactionID, reason: nil) {
|
||||||
|
@ -56,21 +56,21 @@ protocol TimelineControllerProtocol {
|
|||||||
inReplyToEventID: String?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async
|
intentionalMentions: IntentionalMentions) async
|
||||||
|
|
||||||
func edit(_ eventOrTransactionID: EventOrTransactionId,
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async
|
intentionalMentions: IntentionalMentions) async
|
||||||
|
|
||||||
func editCaption(_ eventOrTransactionID: EventOrTransactionId,
|
func editCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async
|
intentionalMentions: IntentionalMentions) async
|
||||||
|
|
||||||
func removeCaption(_ eventOrTransactionID: EventOrTransactionId) async
|
func removeCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to eventOrTransactionID: EventOrTransactionId) async
|
func toggleReaction(_ reaction: String, to eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async
|
||||||
|
|
||||||
func redact(_ eventOrTransactionID: EventOrTransactionId) async
|
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async
|
||||||
|
|
||||||
func pin(eventID: String) async
|
func pin(eventID: String) async
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import MatrixRustSDK
|
@preconcurrency import MatrixRustSDK
|
||||||
|
|
||||||
/// A timeline item identifier
|
/// A timeline item identifier
|
||||||
/// - uniqueID: Stable id across state changes of the timeline item, it uniquely identifies an item in a timeline.
|
/// - uniqueID: Stable id across state changes of the timeline item, it uniquely identifies an item in a timeline.
|
||||||
@ -14,42 +14,63 @@ import MatrixRustSDK
|
|||||||
/// - eventOrTransactionID: Contains the 2 possible identifiers of an event, either it has a remote event id or
|
/// - 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.
|
/// a local transaction id, never both or none.
|
||||||
enum TimelineItemIdentifier: Hashable, Sendable {
|
enum TimelineItemIdentifier: Hashable, Sendable {
|
||||||
case event(uniqueID: TimelineUniqueId, eventOrTransactionID: EventOrTransactionId)
|
struct UniqueID: Hashable {
|
||||||
case virtual(uniqueID: TimelineUniqueId)
|
let value: String
|
||||||
|
|
||||||
var uniqueID: TimelineUniqueId {
|
init(_ value: String) {
|
||||||
switch self {
|
self.value = value
|
||||||
case .event(let uniqueID, _):
|
|
||||||
return uniqueID
|
|
||||||
case .virtual(let uniqueID):
|
|
||||||
return uniqueID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init(rustValue: TimelineUniqueId) {
|
||||||
|
self.init(rustValue.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rustValue: TimelineUniqueId {
|
||||||
|
.init(id: value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EventOrTransactionID: Hashable {
|
||||||
|
case eventID(String), transactionID(String)
|
||||||
|
|
||||||
|
init(rustValue: EventOrTransactionId) {
|
||||||
|
switch rustValue {
|
||||||
|
case .eventId(let eventID): self = .eventID(eventID)
|
||||||
|
case .transactionId(let transactionID): self = .transactionID(transactionID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rustValue: EventOrTransactionId {
|
||||||
|
switch self {
|
||||||
|
case .eventID(let eventID): .eventId(eventId: eventID)
|
||||||
|
case .transactionID(let transactionID): .transactionId(transactionId: transactionID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case event(uniqueID: UniqueID, eventOrTransactionID: EventOrTransactionID)
|
||||||
|
case virtual(uniqueID: UniqueID)
|
||||||
|
|
||||||
|
var uniqueID: UniqueID {
|
||||||
|
switch self {
|
||||||
|
case .event(let uniqueID, _): uniqueID
|
||||||
|
case .virtual(let uniqueID): uniqueID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventOrTransactionID: EventOrTransactionID? {
|
||||||
|
guard case let .event(_, eventOrTransactionID) = self else { return nil }
|
||||||
|
return eventOrTransactionID
|
||||||
}
|
}
|
||||||
|
|
||||||
var eventID: String? {
|
var eventID: String? {
|
||||||
guard case let .event(_, eventOrTransactionID) = self else {
|
guard case let .event(_, .eventID(eventID)) = self else { return nil }
|
||||||
return nil
|
return eventID
|
||||||
}
|
|
||||||
|
|
||||||
switch eventOrTransactionID {
|
|
||||||
case .eventId(let eventID):
|
|
||||||
return eventID
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var transactionID: String? {
|
var transactionID: String? {
|
||||||
guard case let .event(_, eventOrTransactionID) = self else {
|
guard case let .event(_, .transactionID(transactionID)) = self else { return nil }
|
||||||
return nil
|
return transactionID
|
||||||
}
|
|
||||||
|
|
||||||
switch eventOrTransactionID {
|
|
||||||
case .transactionId(let transactionID):
|
|
||||||
return transactionID
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +78,10 @@ enum TimelineItemIdentifier: Hashable, Sendable {
|
|||||||
|
|
||||||
extension TimelineItemIdentifier {
|
extension TimelineItemIdentifier {
|
||||||
static var randomEvent: Self {
|
static var randomEvent: Self {
|
||||||
.event(uniqueID: .init(id: UUID().uuidString), eventOrTransactionID: .eventId(eventId: UUID().uuidString))
|
.event(uniqueID: .init(UUID().uuidString), eventOrTransactionID: .eventID(UUID().uuidString))
|
||||||
}
|
}
|
||||||
|
|
||||||
static var randomVirtual: Self {
|
static var randomVirtual: Self {
|
||||||
.virtual(uniqueID: .init(id: UUID().uuidString))
|
.virtual(uniqueID: .init(UUID().uuidString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,14 @@ import MatrixRustSDK
|
|||||||
/// A light wrapper around timeline items returned from Rust.
|
/// A light wrapper around timeline items returned from Rust.
|
||||||
enum TimelineItemProxy {
|
enum TimelineItemProxy {
|
||||||
case event(EventTimelineItemProxy)
|
case event(EventTimelineItemProxy)
|
||||||
case virtual(MatrixRustSDK.VirtualTimelineItem, uniqueID: TimelineUniqueId)
|
case virtual(MatrixRustSDK.VirtualTimelineItem, uniqueID: TimelineItemIdentifier.UniqueID)
|
||||||
case unknown(MatrixRustSDK.TimelineItem)
|
case unknown(MatrixRustSDK.TimelineItem)
|
||||||
|
|
||||||
init(item: MatrixRustSDK.TimelineItem) {
|
init(item: MatrixRustSDK.TimelineItem) {
|
||||||
if let eventItem = item.asEvent() {
|
if let eventItem = item.asEvent() {
|
||||||
self = .event(EventTimelineItemProxy(item: eventItem, uniqueID: item.uniqueId()))
|
self = .event(EventTimelineItemProxy(item: eventItem, uniqueID: .init(rustValue: item.uniqueId())))
|
||||||
} else if let virtualItem = item.asVirtual() {
|
} else if let virtualItem = item.asVirtual() {
|
||||||
self = .virtual(virtualItem, uniqueID: item.uniqueId())
|
self = .virtual(virtualItem, uniqueID: .init(rustValue: item.uniqueId()))
|
||||||
} else {
|
} else {
|
||||||
self = .unknown(item)
|
self = .unknown(item)
|
||||||
}
|
}
|
||||||
@ -71,10 +71,10 @@ class EventTimelineItemProxy {
|
|||||||
let item: MatrixRustSDK.EventTimelineItem
|
let item: MatrixRustSDK.EventTimelineItem
|
||||||
let id: TimelineItemIdentifier
|
let id: TimelineItemIdentifier
|
||||||
|
|
||||||
init(item: MatrixRustSDK.EventTimelineItem, uniqueID: TimelineUniqueId) {
|
init(item: MatrixRustSDK.EventTimelineItem, uniqueID: TimelineItemIdentifier.UniqueID) {
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
id = .event(uniqueID: uniqueID, eventOrTransactionID: item.eventOrTransactionId)
|
id = .event(uniqueID: uniqueID, eventOrTransactionID: .init(rustValue: item.eventOrTransactionId))
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var deliveryStatus: TimelineItemDeliveryStatus? = {
|
lazy var deliveryStatus: TimelineItemDeliveryStatus? = {
|
||||||
@ -211,8 +211,8 @@ struct SendHandleProxy: Hashable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static var mock: SendHandleProxy {
|
static var mock: SendHandleProxy {
|
||||||
.init(itemID: .event(uniqueID: .init(id: UUID().uuidString),
|
.init(itemID: .event(uniqueID: .init(UUID().uuidString),
|
||||||
eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
|
eventOrTransactionID: .eventID(UUID().uuidString)),
|
||||||
underlyingHandle: .init(noPointer: .init()))
|
underlyingHandle: .init(noPointer: .init()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,6 @@ struct PaginationIndicatorRoomTimelineItem: DecorationTimelineItemProtocol, Equa
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(position: Position) {
|
init(position: Position) {
|
||||||
id = .virtual(uniqueID: .init(id: position.id))
|
id = .virtual(uniqueID: .init(position.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
struct TimelineStartRoomTimelineItem: DecorationTimelineItemProtocol, Equatable {
|
||||||
let id: TimelineItemIdentifier = .virtual(uniqueID: .init(id: UUID().uuidString))
|
let id: TimelineItemIdentifier = .virtual(uniqueID: .init(UUID().uuidString))
|
||||||
let name: String?
|
let name: String?
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ final class RoomTimelineItemViewState: Identifiable, Equatable, ObservableObject
|
|||||||
// MARK: Identifiable
|
// MARK: Identifiable
|
||||||
|
|
||||||
/// The `timelineID` of the item, used for the timeline view level identification, do not use for any business logic use `identifier` instead
|
/// The `timelineID` of the item, used for the timeline view level identification, do not use for any business logic use `identifier` instead
|
||||||
var id: TimelineUniqueId {
|
var id: TimelineItemIdentifier.UniqueID {
|
||||||
identifier.uniqueID
|
identifier.uniqueID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,9 +166,9 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func edit(_ eventOrTransactionID: EventOrTransactionId, newContent: EditedContent) async -> Result<Void, TimelineProxyError> {
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, newContent: EditedContent) async -> Result<Void, TimelineProxyError> {
|
||||||
do {
|
do {
|
||||||
try await timeline.edit(eventOrTransactionId: eventOrTransactionID, newContent: newContent)
|
try await timeline.edit(eventOrTransactionId: eventOrTransactionID.rustValue, newContent: newContent)
|
||||||
|
|
||||||
MXLog.info("Finished editing timeline item: \(eventOrTransactionID)")
|
MXLog.info("Finished editing timeline item: \(eventOrTransactionID)")
|
||||||
|
|
||||||
@ -179,11 +179,11 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func redact(_ eventOrTransactionID: EventOrTransactionId, reason: String?) async -> Result<Void, TimelineProxyError> {
|
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID, reason: String?) async -> Result<Void, TimelineProxyError> {
|
||||||
MXLog.info("Redacting timeline item: \(eventOrTransactionID)")
|
MXLog.info("Redacting timeline item: \(eventOrTransactionID)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await timeline.redactEvent(eventOrTransactionId: eventOrTransactionID, reason: reason)
|
try await timeline.redactEvent(eventOrTransactionId: eventOrTransactionID.rustValue, reason: reason)
|
||||||
|
|
||||||
MXLog.info("Redacted timeline item: \(eventOrTransactionID)")
|
MXLog.info("Redacted timeline item: \(eventOrTransactionID)")
|
||||||
|
|
||||||
@ -443,11 +443,11 @@ final class TimelineProxy: TimelineProxyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to eventOrTransactionID: EventOrTransactionId) async -> Result<Void, TimelineProxyError> {
|
func toggleReaction(_ reaction: String, to eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async -> Result<Void, TimelineProxyError> {
|
||||||
MXLog.info("Toggling reaction \(reaction) for event: \(eventOrTransactionID)")
|
MXLog.info("Toggling reaction \(reaction) for event: \(eventOrTransactionID)")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await timeline.toggleReaction(itemId: eventOrTransactionID, key: reaction)
|
try await timeline.toggleReaction(itemId: eventOrTransactionID.rustValue, key: reaction)
|
||||||
MXLog.info("Finished toggling reaction for event: \(eventOrTransactionID)")
|
MXLog.info("Finished toggling reaction for event: \(eventOrTransactionID)")
|
||||||
return .success(())
|
return .success(())
|
||||||
} catch {
|
} catch {
|
||||||
@ -650,7 +650,7 @@ extension Array where Element == TimelineItemProxy {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstEventTimelineItemUsingEventOrTransactionID(_ eventOrTransactionID: EventOrTransactionId) -> EventTimelineItem? {
|
func firstEventTimelineItemUsingEventOrTransactionID(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) -> EventTimelineItem? {
|
||||||
for item in self {
|
for item in self {
|
||||||
if case let .event(eventTimelineItem) = item,
|
if case let .event(eventTimelineItem) = item,
|
||||||
case let .event(_, identifier) = eventTimelineItem.id,
|
case let .event(_, identifier) = eventTimelineItem.id,
|
||||||
|
@ -40,10 +40,10 @@ 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(_ eventOrTransactionID: EventOrTransactionId,
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
newContent: EditedContent) async -> Result<Void, TimelineProxyError>
|
newContent: EditedContent) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func redact(_ eventOrTransactionID: EventOrTransactionId,
|
func redact(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
reason: String?) async -> Result<Void, TimelineProxyError>
|
reason: String?) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func pin(eventID: String) async -> Result<Bool, TimelineProxyError>
|
func pin(eventID: String) async -> Result<Bool, TimelineProxyError>
|
||||||
@ -94,7 +94,7 @@ protocol TimelineProxyProtocol {
|
|||||||
inReplyToEventID: String?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
|
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
func toggleReaction(_ reaction: String, to eventID: EventOrTransactionId) async -> Result<Void, TimelineProxyError>
|
func toggleReaction(_ reaction: String, to eventID: TimelineItemIdentifier.EventOrTransactionID) async -> Result<Void, TimelineProxyError>
|
||||||
|
|
||||||
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>
|
||||||
|
|
||||||
|
@ -32,14 +32,14 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testComposerFocus() {
|
func testComposerFocus() {
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventId(eventId: "mock"), type: .default)))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)))
|
||||||
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(originalEventOrTransactionID: .eventId(eventId: "mock"), type: .default)
|
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)
|
||||||
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)
|
||||||
@ -47,7 +47,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testComposerModeIsPublished() {
|
func testComposerModeIsPublished() {
|
||||||
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventId(eventId: "mock"), type: .default)
|
let mode: ComposerMode = .edit(originalEventOrTransactionID: .eventID("mock"), type: .default)
|
||||||
let expectation = expectation(description: "Composer mode is published")
|
let expectation = expectation(description: "Composer mode is published")
|
||||||
let cancellable = viewModel
|
let cancellable = viewModel
|
||||||
.context
|
.context
|
||||||
@ -229,7 +229,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.context.composerFormattingEnabled = false
|
viewModel.context.composerFormattingEnabled = false
|
||||||
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventId(eventId: "testID"), type: .default)))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventID("testID"), type: .default)))
|
||||||
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
viewModel.context.plainComposerText = .init(string: "Hello world!")
|
||||||
viewModel.saveDraft()
|
viewModel.saveDraft()
|
||||||
|
|
||||||
@ -388,7 +388,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(originalEventOrTransactionID: .eventId(eventId: "testID"), type: .default))
|
XCTAssertEqual(viewModel.state.composerMode, .edit(originalEventOrTransactionID: .eventID("testID"), type: .default))
|
||||||
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world!"))
|
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +476,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(originalEventOrTransactionID: .eventId(eventId: UUID().uuidString), type: .default)))
|
viewModel.process(timelineAction: .setMode(mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .default)))
|
||||||
|
|
||||||
let draft = draftServiceMock.saveVolatileDraftReceivedDraft
|
let draft = draftServiceMock.saveVolatileDraftReceivedDraft
|
||||||
XCTAssertNotNil(draft)
|
XCTAssertNotNil(draft)
|
||||||
|
@ -194,25 +194,25 @@ class LoggingTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let content = try String(contentsOf: logFile)
|
let content = try String(contentsOf: logFile)
|
||||||
XCTAssertTrue(content.contains(textMessage.id.uniqueID.id))
|
XCTAssertTrue(content.contains(textMessage.id.uniqueID.value))
|
||||||
XCTAssertFalse(content.contains(textMessage.body))
|
XCTAssertFalse(content.contains(textMessage.body))
|
||||||
XCTAssertFalse(content.contains(textAttributedString))
|
XCTAssertFalse(content.contains(textAttributedString))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(noticeMessage.id.uniqueID.id))
|
XCTAssertTrue(content.contains(noticeMessage.id.uniqueID.value))
|
||||||
XCTAssertFalse(content.contains(noticeMessage.body))
|
XCTAssertFalse(content.contains(noticeMessage.body))
|
||||||
XCTAssertFalse(content.contains(noticeAttributedString))
|
XCTAssertFalse(content.contains(noticeAttributedString))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(emoteMessage.id.uniqueID.id))
|
XCTAssertTrue(content.contains(emoteMessage.id.uniqueID.value))
|
||||||
XCTAssertFalse(content.contains(emoteMessage.body))
|
XCTAssertFalse(content.contains(emoteMessage.body))
|
||||||
XCTAssertFalse(content.contains(emoteAttributedString))
|
XCTAssertFalse(content.contains(emoteAttributedString))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(imageMessage.id.uniqueID.id))
|
XCTAssertTrue(content.contains(imageMessage.id.uniqueID.value))
|
||||||
XCTAssertFalse(content.contains(imageMessage.body))
|
XCTAssertFalse(content.contains(imageMessage.body))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(videoMessage.id.uniqueID.id))
|
XCTAssertTrue(content.contains(videoMessage.id.uniqueID.value))
|
||||||
XCTAssertFalse(content.contains(videoMessage.body))
|
XCTAssertFalse(content.contains(videoMessage.body))
|
||||||
|
|
||||||
XCTAssertTrue(content.contains(fileMessage.id.uniqueID.id))
|
XCTAssertTrue(content.contains(fileMessage.id.uniqueID.value))
|
||||||
XCTAssertFalse(content.contains(fileMessage.body))
|
XCTAssertFalse(content.contains(fileMessage.body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import XCTest
|
|||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class MessageForwardingScreenViewModelTests: XCTestCase {
|
class MessageForwardingScreenViewModelTests: XCTestCase {
|
||||||
let forwardingItem = MessageForwardingItem(id: .event(uniqueID: .init(id: "t1"), eventOrTransactionID: .eventId(eventId: "t1")),
|
let forwardingItem = MessageForwardingItem(id: .event(uniqueID: .init("t1"), eventOrTransactionID: .eventID("t1")),
|
||||||
roomID: "1",
|
roomID: "1",
|
||||||
content: .init(noPointer: .init()))
|
content: .init(noPointer: .init()))
|
||||||
var viewModel: MessageForwardingScreenViewModelProtocol!
|
var viewModel: MessageForwardingScreenViewModelProtocol!
|
||||||
|
@ -70,8 +70,8 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
let providerUpdateSubject = PassthroughSubject<([TimelineItemProxy], PaginationState), Never>()
|
let providerUpdateSubject = PassthroughSubject<([TimelineItemProxy], PaginationState), Never>()
|
||||||
pinnedTimelineProviderMock.underlyingUpdatePublisher = providerUpdateSubject.eraseToAnyPublisher()
|
pinnedTimelineProviderMock.underlyingUpdatePublisher = providerUpdateSubject.eraseToAnyPublisher()
|
||||||
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
||||||
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init(id: "1"))),
|
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init("1"))),
|
||||||
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init(id: "2")))]
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init("2")))]
|
||||||
|
|
||||||
// check if the banner is now in a loaded state and is showing the counter
|
// check if the banner is now in a loaded state and is showing the counter
|
||||||
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
||||||
@ -87,9 +87,9 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
deferred = deferFulfillment(viewModel.context.$viewState) { viewState in
|
||||||
viewState.pinnedEventsBannerState.count == 3
|
viewState.pinnedEventsBannerState.count == 3
|
||||||
}
|
}
|
||||||
providerUpdateSubject.send(([.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init(id: "1"))),
|
providerUpdateSubject.send(([.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init("1"))),
|
||||||
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init(id: "2"))),
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init("2"))),
|
||||||
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: .init(id: "3")))], .initial))
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: .init("3")))], .initial))
|
||||||
try await deferred.fulfill()
|
try await deferred.fulfill()
|
||||||
XCTAssertFalse(viewModel.context.viewState.pinnedEventsBannerState.isLoading)
|
XCTAssertFalse(viewModel.context.viewState.pinnedEventsBannerState.isLoading)
|
||||||
XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner)
|
XCTAssertTrue(viewModel.context.viewState.shouldShowPinnedEventsBanner)
|
||||||
@ -110,9 +110,9 @@ class RoomScreenViewModelTests: XCTestCase {
|
|||||||
let pinnedTimelineProviderMock = TimelineProviderMock()
|
let pinnedTimelineProviderMock = TimelineProviderMock()
|
||||||
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
pinnedTimelineMock.timelineProvider = pinnedTimelineProviderMock
|
||||||
pinnedTimelineProviderMock.underlyingUpdatePublisher = Empty<([TimelineItemProxy], PaginationState), Never>().eraseToAnyPublisher()
|
pinnedTimelineProviderMock.underlyingUpdatePublisher = Empty<([TimelineItemProxy], PaginationState), Never>().eraseToAnyPublisher()
|
||||||
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init(id: "1"))),
|
pinnedTimelineProviderMock.itemProxies = [.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test1")), uniqueID: .init("1"))),
|
||||||
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init(id: "2"))),
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test2")), uniqueID: .init("2"))),
|
||||||
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: .init(id: "3")))]
|
.event(.init(item: EventTimelineItem(configuration: .init(eventID: "test3")), uniqueID: .init("3")))]
|
||||||
roomProxyMock.underlyingPinnedEventsTimeline = pinnedTimelineMock
|
roomProxyMock.underlyingPinnedEventsTimeline = pinnedTimelineMock
|
||||||
let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(),
|
let viewModel = RoomScreenViewModel(clientProxy: ClientProxyMock(),
|
||||||
roomProxy: roomProxyMock,
|
roomProxy: roomProxyMock,
|
||||||
|
@ -22,7 +22,7 @@ class TimelineItemFactoryTests: XCTestCase {
|
|||||||
|
|
||||||
let eventTimelineItem = EventTimelineItem.mockCallInvite(sender: senderUserID)
|
let eventTimelineItem = EventTimelineItem.mockCallInvite(sender: senderUserID)
|
||||||
|
|
||||||
let eventTimelineItemProxy = EventTimelineItemProxy(item: eventTimelineItem, uniqueID: .init(id: "0"))
|
let eventTimelineItemProxy = EventTimelineItemProxy(item: eventTimelineItem, uniqueID: .init("0"))
|
||||||
|
|
||||||
let item = factory.buildTimelineItem(for: eventTimelineItemProxy, isDM: false)
|
let item = factory.buildTimelineItem(for: eventTimelineItemProxy, isDM: false)
|
||||||
|
|
||||||
|
@ -259,9 +259,9 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
|
|
||||||
func testSendReadReceiptWithoutEvents() async throws {
|
func testSendReadReceiptWithoutEvents() async throws {
|
||||||
// Given a room with only virtual items.
|
// Given a room with only virtual items.
|
||||||
let items = [SeparatorRoomTimelineItem(uniqueID: .init(id: "v1")),
|
let items = [SeparatorRoomTimelineItem(uniqueID: .init("v1")),
|
||||||
SeparatorRoomTimelineItem(uniqueID: .init(id: "v2")),
|
SeparatorRoomTimelineItem(uniqueID: .init("v2")),
|
||||||
SeparatorRoomTimelineItem(uniqueID: .init(id: "v3"))]
|
SeparatorRoomTimelineItem(uniqueID: .init("v3"))]
|
||||||
let (viewModel, _, timelineProxy, _) = readReceiptsConfiguration(with: items)
|
let (viewModel, _, timelineProxy, _) = readReceiptsConfiguration(with: items)
|
||||||
|
|
||||||
// When sending a read receipt for the last item.
|
// When sending a read receipt for the last item.
|
||||||
@ -276,7 +276,7 @@ class TimelineViewModelTests: XCTestCase {
|
|||||||
// Given a room where the last event is a virtual item.
|
// Given a room where the last event is a virtual item.
|
||||||
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
|
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
|
||||||
TextRoomTimelineItem(eventID: "t2"),
|
TextRoomTimelineItem(eventID: "t2"),
|
||||||
SeparatorRoomTimelineItem(uniqueID: .init(id: "v3"))]
|
SeparatorRoomTimelineItem(uniqueID: .init("v3"))]
|
||||||
let (viewModel, _, _, _) = readReceiptsConfiguration(with: items)
|
let (viewModel, _, _, _) = readReceiptsConfiguration(with: items)
|
||||||
|
|
||||||
// When sending a read receipt for the last item.
|
// When sending a read receipt for the last item.
|
||||||
@ -445,14 +445,14 @@ private extension TextRoomTimelineItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private extension SeparatorRoomTimelineItem {
|
private extension SeparatorRoomTimelineItem {
|
||||||
init(uniqueID: TimelineUniqueId) {
|
init(uniqueID: TimelineItemIdentifier.UniqueID) {
|
||||||
self.init(id: .virtual(uniqueID: uniqueID), timestamp: .mock)
|
self.init(id: .virtual(uniqueID: uniqueID), timestamp: .mock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension TextRoomTimelineItem {
|
private extension TextRoomTimelineItem {
|
||||||
init(eventID: String) {
|
init(eventID: String) {
|
||||||
self.init(id: .event(uniqueID: .init(id: UUID().uuidString), eventOrTransactionID: .eventId(eventId: eventID)),
|
self.init(id: .event(uniqueID: .init(UUID().uuidString), eventOrTransactionID: .eventID(eventID)),
|
||||||
timestamp: .mock,
|
timestamp: .mock,
|
||||||
isOutgoing: false,
|
isOutgoing: false,
|
||||||
isEditable: false,
|
isEditable: false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user