mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
SDK Changes Refactor (#1312)
* internal id * notification refactor * client proxy refactor * required self * better identifier system * using the event id when required * tests fixed * tested some stuff * fixed merge conflict * improved the test wait * animation disabled * Bump Rust SDK version to 1.0.98-alpha (#1310) * code improvement * pause sync * pr suggestions * result * Apply suggestions from code review Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> * enum based debug identifier --------- Co-authored-by: aringenbach <80891108+aringenbach@users.noreply.github.com> Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>
This commit is contained in:
@@ -18,11 +18,11 @@ import SwiftUI
|
||||
|
||||
struct EmojiPickerScreenCoordinatorParameters {
|
||||
let emojiProvider: EmojiProviderProtocol
|
||||
let itemId: String
|
||||
let itemID: TimelineItemIdentifier
|
||||
}
|
||||
|
||||
enum EmojiPickerScreenCoordinatorAction {
|
||||
case emojiSelected(emoji: String, itemId: String)
|
||||
case emojiSelected(emoji: String, itemID: TimelineItemIdentifier)
|
||||
case dismiss
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ final class EmojiPickerScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
switch action {
|
||||
case let .emojiSelected(emoji: emoji):
|
||||
self.callback?(.emojiSelected(emoji: emoji, itemId: self.parameters.itemId))
|
||||
self.callback?(.emojiSelected(emoji: emoji, itemID: self.parameters.itemID))
|
||||
case .dismiss:
|
||||
self.callback?(.dismiss)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct ReportContentScreenCoordinatorParameters {
|
||||
let itemID: String
|
||||
let eventID: String
|
||||
let senderID: String
|
||||
let roomProxy: RoomProxyProtocol
|
||||
weak var userIndicatorController: UserIndicatorControllerProtocol?
|
||||
@@ -39,7 +39,7 @@ final class ReportContentScreenCoordinator: CoordinatorProtocol {
|
||||
init(parameters: ReportContentScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = ReportContentScreenViewModel(itemID: parameters.itemID, senderID: parameters.senderID, roomProxy: parameters.roomProxy)
|
||||
viewModel = ReportContentScreenViewModel(eventID: parameters.eventID, senderID: parameters.senderID, roomProxy: parameters.roomProxy)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
@@ -20,7 +20,7 @@ import SwiftUI
|
||||
typealias ReportContentScreenViewModelType = StateStoreViewModel<ReportContentScreenViewState, ReportContentScreenViewAction>
|
||||
|
||||
class ReportContentScreenViewModel: ReportContentScreenViewModelType, ReportContentScreenViewModelProtocol {
|
||||
private let itemID: String
|
||||
private let eventID: String
|
||||
private let senderID: String
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private let actionsSubject: PassthroughSubject<ReportContentScreenViewModelAction, Never> = .init()
|
||||
@@ -29,8 +29,8 @@ class ReportContentScreenViewModel: ReportContentScreenViewModelType, ReportCont
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(itemID: String, senderID: String, roomProxy: RoomProxyProtocol) {
|
||||
self.itemID = itemID
|
||||
init(eventID: String, senderID: String, roomProxy: RoomProxyProtocol) {
|
||||
self.eventID = eventID
|
||||
self.senderID = senderID
|
||||
self.roomProxy = roomProxy
|
||||
|
||||
@@ -53,7 +53,7 @@ class ReportContentScreenViewModel: ReportContentScreenViewModelType, ReportCont
|
||||
private func submitReport() async {
|
||||
actionsSubject.send(.submitStarted)
|
||||
|
||||
if case let .failure(error) = await roomProxy.reportContent(itemID, reason: state.bindings.reasonText) {
|
||||
if case let .failure(error) = await roomProxy.reportContent(eventID, reason: state.bindings.reasonText) {
|
||||
MXLog.error("Submit Report Content failed: \(error)")
|
||||
actionsSubject.send(.submitFailed(error: error))
|
||||
return
|
||||
|
||||
@@ -84,7 +84,7 @@ struct ReportContentScreen: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct ReportContentScreen_Previews: PreviewProvider {
|
||||
static let viewModel = ReportContentScreenViewModel(itemID: "",
|
||||
static let viewModel = ReportContentScreenViewModel(eventID: "",
|
||||
senderID: "",
|
||||
roomProxy: RoomProxyMock(with: .init(displayName: nil)))
|
||||
|
||||
|
||||
@@ -25,15 +25,15 @@ struct RoomScreenCoordinatorParameters {
|
||||
}
|
||||
|
||||
enum RoomScreenCoordinatorAction {
|
||||
case presentReportContent(itemID: String, senderID: String)
|
||||
case presentReportContent(itemID: TimelineItemIdentifier, senderID: String)
|
||||
case presentMediaUploadPicker(MediaPickerScreenSource)
|
||||
case presentMediaUploadPreviewScreen(URL)
|
||||
case presentRoomDetails
|
||||
case presentLocationPicker
|
||||
case presentLocationViewer(body: String, geoURI: GeoURI, description: String?)
|
||||
case presentEmojiPicker(itemID: String)
|
||||
case presentEmojiPicker(itemID: TimelineItemIdentifier)
|
||||
case presentRoomMemberDetails(member: RoomMemberProxyProtocol)
|
||||
case presentMessageForwarding(itemID: String)
|
||||
case presentMessageForwarding(itemID: TimelineItemIdentifier)
|
||||
}
|
||||
|
||||
final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
@@ -22,22 +22,22 @@ import OrderedCollections
|
||||
|
||||
enum RoomScreenViewModelAction {
|
||||
case displayRoomDetails
|
||||
case displayEmojiPicker(itemID: String)
|
||||
case displayReportContent(itemID: String, senderID: String)
|
||||
case displayEmojiPicker(itemID: TimelineItemIdentifier)
|
||||
case displayReportContent(itemID: TimelineItemIdentifier, senderID: String)
|
||||
case displayCameraPicker
|
||||
case displayMediaPicker
|
||||
case displayDocumentPicker
|
||||
case displayLocationPicker
|
||||
case displayMediaUploadPreviewScreen(url: URL)
|
||||
case displayRoomMemberDetails(member: RoomMemberProxyProtocol)
|
||||
case displayMessageForwarding(itemID: String)
|
||||
case displayMessageForwarding(itemID: TimelineItemIdentifier)
|
||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
||||
}
|
||||
|
||||
enum RoomScreenComposerMode: Equatable {
|
||||
case `default`
|
||||
case reply(itemID: String, replyDetails: TimelineItemReplyDetails)
|
||||
case edit(originalItemId: String)
|
||||
case reply(itemID: TimelineItemIdentifier, replyDetails: TimelineItemReplyDetails)
|
||||
case edit(originalItemId: TimelineItemIdentifier)
|
||||
|
||||
var isEdit: Bool {
|
||||
switch self {
|
||||
@@ -52,21 +52,21 @@ enum RoomScreenComposerMode: Equatable {
|
||||
enum RoomScreenViewAction {
|
||||
case displayRoomDetails
|
||||
case paginateBackwards
|
||||
case itemAppeared(id: String)
|
||||
case itemDisappeared(id: String)
|
||||
case itemTapped(id: String)
|
||||
case itemAppeared(itemID: TimelineItemIdentifier)
|
||||
case itemDisappeared(itemID: TimelineItemIdentifier)
|
||||
case itemTapped(itemID: TimelineItemIdentifier)
|
||||
case linkClicked(url: URL)
|
||||
case sendMessage
|
||||
case toggleReaction(key: String, eventID: String)
|
||||
case toggleReaction(key: String, itemID: TimelineItemIdentifier)
|
||||
case cancelReply
|
||||
case cancelEdit
|
||||
/// Mark the entire room as read - this is heavy handed as a starting point for now.
|
||||
case markRoomAsRead
|
||||
|
||||
case timelineItemMenu(itemID: String)
|
||||
case timelineItemMenuAction(itemID: String, action: TimelineItemMenuAction)
|
||||
case timelineItemMenu(itemID: TimelineItemIdentifier)
|
||||
case timelineItemMenuAction(itemID: TimelineItemIdentifier, action: TimelineItemMenuAction)
|
||||
|
||||
case displayEmojiPicker(itemID: String)
|
||||
case displayEmojiPicker(itemID: TimelineItemIdentifier)
|
||||
|
||||
case displayCameraPicker
|
||||
case displayMediaPicker
|
||||
@@ -76,10 +76,10 @@ enum RoomScreenViewAction {
|
||||
case handlePasteOrDrop(provider: NSItemProvider)
|
||||
case tappedOnUser(userID: String)
|
||||
|
||||
case reactionSummary(itemID: String, key: String)
|
||||
case reactionSummary(itemID: TimelineItemIdentifier, key: String)
|
||||
|
||||
case retrySend(transactionID: String?)
|
||||
case cancelSend(transactionID: String?)
|
||||
case retrySend(itemID: TimelineItemIdentifier)
|
||||
case cancelSend(itemID: TimelineItemIdentifier)
|
||||
}
|
||||
|
||||
struct RoomScreenViewState: BindableState {
|
||||
@@ -97,7 +97,7 @@ struct RoomScreenViewState: BindableState {
|
||||
|
||||
var bindings: RoomScreenViewStateBindings
|
||||
|
||||
var timelineItemMenuActionProvider: (@MainActor (_ itemId: String) -> TimelineItemMenuActions?)?
|
||||
var timelineItemMenuActionProvider: (@MainActor (_ itemId: TimelineItemIdentifier) -> TimelineItemMenuActions?)?
|
||||
|
||||
var composerMode: RoomScreenComposerMode = .default
|
||||
|
||||
@@ -105,7 +105,7 @@ struct RoomScreenViewState: BindableState {
|
||||
bindings.composerText.count == 0
|
||||
}
|
||||
|
||||
var itemIDs: [String] {
|
||||
var timelineIDs: [String] {
|
||||
itemsDictionary.keys.elements
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ struct RoomScreenViewStateBindings {
|
||||
|
||||
/// The state of wether reactions listed on the timeline are expanded/collapsed.
|
||||
/// Key is itemID, value is the collapsed state.
|
||||
var reactionsCollapsed: [String: Bool]
|
||||
var reactionsCollapsed: [TimelineItemIdentifier: Bool]
|
||||
|
||||
/// A media item that will be previewed with QuickLook.
|
||||
var mediaPreviewItem: MediaPreviewItem?
|
||||
@@ -146,14 +146,14 @@ struct RoomScreenViewStateBindings {
|
||||
var reactionSummaryInfo: ReactionSummaryInfo?
|
||||
}
|
||||
|
||||
struct TimelineItemActionMenuInfo: Identifiable, Equatable {
|
||||
struct TimelineItemActionMenuInfo: Equatable, Identifiable {
|
||||
static func == (lhs: TimelineItemActionMenuInfo, rhs: TimelineItemActionMenuInfo) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
|
||||
let item: EventBasedTimelineItemProtocol
|
||||
|
||||
var id: String {
|
||||
var id: TimelineItemIdentifier {
|
||||
item.id
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ struct TimelineItemActionMenuInfo: Identifiable, Equatable {
|
||||
struct SendFailedConfirmationDialogInfo: ConfirmationDialogProtocol {
|
||||
let title = L10n.screenRoomRetrySendMenuTitle
|
||||
|
||||
let transactionID: String?
|
||||
let itemID: TimelineItemIdentifier
|
||||
}
|
||||
|
||||
struct ReactionSummaryInfo: Identifiable {
|
||||
|
||||
@@ -120,14 +120,14 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
case .tappedOnUser(userID: let userID):
|
||||
Task { await handleTappedUser(userID: userID) }
|
||||
case .displayEmojiPicker(let itemID):
|
||||
guard let item = state.itemsDictionary[itemID], item.isReactable else { return }
|
||||
guard let item = state.itemsDictionary[itemID.timelineID], item.isReactable else { return }
|
||||
callback?(.displayEmojiPicker(itemID: itemID))
|
||||
case .reactionSummary(let itemId, let key):
|
||||
showReactionSummary(for: itemId, selectedKey: key)
|
||||
case .retrySend(let transactionID):
|
||||
Task { await handleRetrySend(transactionID: transactionID) }
|
||||
case .cancelSend(let transactionID):
|
||||
Task { await handleCancelSend(transactionID: transactionID) }
|
||||
case .reactionSummary(let itemID, let key):
|
||||
showReactionSummary(for: itemID, selectedKey: key)
|
||||
case .retrySend(let itemID):
|
||||
Task { await handleRetrySend(itemID: itemID) }
|
||||
case .cancelSend(let itemID):
|
||||
Task { await handleCancelSend(itemID: itemID) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,9 +221,9 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
_ = await timelineController.markRoomAsRead()
|
||||
}
|
||||
|
||||
private func itemTapped(with itemId: String) async {
|
||||
private func itemTapped(with itemID: TimelineItemIdentifier) async {
|
||||
state.showLoading = true
|
||||
let action = await timelineController.processItemTap(itemId)
|
||||
let action = await timelineController.processItemTap(itemID)
|
||||
|
||||
switch action {
|
||||
case .displayMediaFile(let file, let title):
|
||||
@@ -252,19 +252,19 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
if itemGroup.count == 1 {
|
||||
if let firstItem = itemGroup.first {
|
||||
timelineItemsDictionary.updateValue(updateViewModel(item: firstItem, groupStyle: .single),
|
||||
forKey: firstItem.id)
|
||||
forKey: firstItem.id.timelineID)
|
||||
}
|
||||
} else {
|
||||
for (index, item) in itemGroup.enumerated() {
|
||||
if index == 0 {
|
||||
timelineItemsDictionary.updateValue(updateViewModel(item: item, groupStyle: .first),
|
||||
forKey: item.id)
|
||||
forKey: item.id.timelineID)
|
||||
} else if index == itemGroup.count - 1 {
|
||||
timelineItemsDictionary.updateValue(updateViewModel(item: item, groupStyle: .last),
|
||||
forKey: item.id)
|
||||
forKey: item.id.timelineID)
|
||||
} else {
|
||||
timelineItemsDictionary.updateValue(updateViewModel(item: item, groupStyle: .middle),
|
||||
forKey: item.id)
|
||||
forKey: item.id.timelineID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
private func updateViewModel(item: RoomTimelineItemProtocol, groupStyle: TimelineGroupStyle) -> RoomTimelineItemViewModel {
|
||||
if let timelineItemViewModel = state.itemsDictionary[item.id] {
|
||||
if let timelineItemViewModel = state.itemsDictionary[item.id.timelineID] {
|
||||
timelineItemViewModel.groupStyle = groupStyle
|
||||
timelineItemViewModel.type = .init(item: item)
|
||||
return timelineItemViewModel
|
||||
@@ -360,7 +360,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
// MARK: TimelineItemActionMenu
|
||||
|
||||
private func showTimelineItemActionMenu(for itemID: String) {
|
||||
private func showTimelineItemActionMenu(for itemID: TimelineItemIdentifier) {
|
||||
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }),
|
||||
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
|
||||
// Don't show a menu for non-event based items.
|
||||
@@ -370,8 +370,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
state.bindings.actionMenuInfo = .init(item: eventTimelineItem)
|
||||
}
|
||||
|
||||
private func timelineItemMenuActionsForItemId(_ itemId: String) -> TimelineItemMenuActions? {
|
||||
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemId }),
|
||||
private func timelineItemMenuActionsForItemId(_ itemID: TimelineItemIdentifier) -> TimelineItemMenuActions? {
|
||||
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }),
|
||||
let item = timelineItem as? EventBasedTimelineItemProtocol else {
|
||||
// Don't show a context menu for non-event based items.
|
||||
return nil
|
||||
@@ -395,7 +395,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
]
|
||||
|
||||
if item.isMessage {
|
||||
actions.append(.forward(itemID: itemId))
|
||||
actions.append(.forward(itemID: itemID))
|
||||
}
|
||||
|
||||
if item.isEditable {
|
||||
@@ -426,7 +426,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity function_body_length
|
||||
private func processTimelineItemMenuAction(_ action: TimelineItemMenuAction, itemID: String) {
|
||||
private func processTimelineItemMenuAction(_ action: TimelineItemMenuAction, itemID: TimelineItemIdentifier) {
|
||||
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }),
|
||||
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
|
||||
return
|
||||
@@ -449,7 +449,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
setComposerMode(.edit(originalItemId: messageTimelineItem.id))
|
||||
case .copyPermalink:
|
||||
do {
|
||||
let permalink = try PermalinkBuilder.permalinkTo(eventIdentifier: eventTimelineItem.id, roomIdentifier: timelineController.roomID,
|
||||
guard let eventID = eventTimelineItem.id.eventID else {
|
||||
displayError(.alert(L10n.errorFailedCreatingThePermalink))
|
||||
break
|
||||
}
|
||||
|
||||
let permalink = try PermalinkBuilder.permalinkTo(eventIdentifier: eventID, roomIdentifier: timelineController.roomID,
|
||||
baseURL: appSettings.permalinkBaseURL)
|
||||
UIPasteboard.general.url = permalink
|
||||
} catch {
|
||||
@@ -457,9 +462,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
case .redact:
|
||||
Task {
|
||||
if eventTimelineItem.hasFailedToSend,
|
||||
let transactionID = eventTimelineItem.properties.transactionID {
|
||||
await timelineController.cancelSend(transactionID)
|
||||
if eventTimelineItem.hasFailedToSend {
|
||||
await timelineController.cancelSend(itemID)
|
||||
} else {
|
||||
await timelineController.redact(itemID)
|
||||
}
|
||||
@@ -567,16 +571,18 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
}
|
||||
|
||||
private func handleRetrySend(transactionID: String?) async {
|
||||
guard let transactionID else {
|
||||
private func handleRetrySend(itemID: TimelineItemIdentifier) async {
|
||||
guard let transactionID = itemID.transactionID else {
|
||||
MXLog.error("Failed Retry Send: missing transaction ID")
|
||||
return
|
||||
}
|
||||
|
||||
await roomProxy.retrySend(transactionID: transactionID)
|
||||
}
|
||||
|
||||
private func handleCancelSend(transactionID: String?) async {
|
||||
guard let transactionID else {
|
||||
private func handleCancelSend(itemID: TimelineItemIdentifier) async {
|
||||
guard let transactionID = itemID.transactionID else {
|
||||
MXLog.error("Failed Cancel Send: missing transaction ID")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -643,7 +649,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
// MARK: - Reaction summary
|
||||
|
||||
private func showReactionSummary(for itemID: String, selectedKey: String) {
|
||||
private func showReactionSummary(for itemID: TimelineItemIdentifier, selectedKey: String) {
|
||||
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }),
|
||||
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
|
||||
return
|
||||
@@ -664,7 +670,7 @@ extension RoomScreenViewModel.Context {
|
||||
/// A function to make it easier to bind to reactions expand/collapsed state
|
||||
/// - Parameter itemID: The id of the timeline item the reacted to
|
||||
/// - Returns: Wether the reactions should show in the collapsed state, true by default.
|
||||
func reactionsCollapsedBinding(for itemID: String) -> Binding<Bool> {
|
||||
func reactionsCollapsedBinding(for itemID: TimelineItemIdentifier) -> Binding<Bool> {
|
||||
Binding(get: {
|
||||
self.reactionsCollapsed[itemID] ?? true
|
||||
}, set: {
|
||||
|
||||
@@ -173,7 +173,7 @@ private struct MessageComposerHeaderLabelStyle: LabelStyle {
|
||||
|
||||
struct MessageComposer_Previews: PreviewProvider {
|
||||
static let viewModel = RoomScreenViewModel.mock
|
||||
|
||||
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
MessageComposer(text: .constant(""),
|
||||
@@ -184,7 +184,7 @@ struct MessageComposer_Previews: PreviewProvider {
|
||||
pasteAction: { _ in },
|
||||
replyCancellationAction: { },
|
||||
editCancellationAction: { })
|
||||
|
||||
|
||||
MessageComposer(text: .constant("This is a short message."),
|
||||
focused: .constant(false),
|
||||
sendingDisabled: false,
|
||||
@@ -193,7 +193,7 @@ struct MessageComposer_Previews: PreviewProvider {
|
||||
pasteAction: { _ in },
|
||||
replyCancellationAction: { },
|
||||
editCancellationAction: { })
|
||||
|
||||
|
||||
MessageComposer(text: .constant("This is a very long message that will wrap to 2 lines on an iPhone 14."),
|
||||
focused: .constant(false),
|
||||
sendingDisabled: false,
|
||||
@@ -202,7 +202,7 @@ struct MessageComposer_Previews: PreviewProvider {
|
||||
pasteAction: { _ in },
|
||||
replyCancellationAction: { },
|
||||
editCancellationAction: { })
|
||||
|
||||
|
||||
MessageComposer(text: .constant("This is an even longer message that will wrap to 3 lines on an iPhone 14, just to see the difference it makes."),
|
||||
focused: .constant(false),
|
||||
sendingDisabled: false,
|
||||
@@ -211,20 +211,20 @@ struct MessageComposer_Previews: PreviewProvider {
|
||||
pasteAction: { _ in },
|
||||
replyCancellationAction: { },
|
||||
editCancellationAction: { })
|
||||
|
||||
|
||||
MessageComposer(text: .constant("Some message"),
|
||||
focused: .constant(false),
|
||||
sendingDisabled: false,
|
||||
mode: .edit(originalItemId: UUID().uuidString),
|
||||
mode: .edit(originalItemId: .init(timelineID: UUID().uuidString)),
|
||||
sendAction: { },
|
||||
pasteAction: { _ in },
|
||||
replyCancellationAction: { },
|
||||
editCancellationAction: { })
|
||||
|
||||
|
||||
MessageComposer(text: .constant(""),
|
||||
focused: .constant(false),
|
||||
sendingDisabled: false,
|
||||
mode: .reply(itemID: UUID().uuidString,
|
||||
mode: .reply(itemID: .init(timelineID: UUID().uuidString),
|
||||
replyDetails: .loaded(sender: .init(id: "Kirk"),
|
||||
contentType: .text(.init(body: "Text: Where the wild things are")))),
|
||||
sendAction: { },
|
||||
@@ -233,7 +233,7 @@ struct MessageComposer_Previews: PreviewProvider {
|
||||
editCancellationAction: { })
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
|
||||
ScrollView {
|
||||
VStack {
|
||||
let replyTypes: [TimelineItemReplyDetails] = [
|
||||
@@ -251,12 +251,12 @@ struct MessageComposer_Previews: PreviewProvider {
|
||||
thumbnailSource: .init(url: .picturesDirectory, mimeType: nil)))),
|
||||
.loading(eventID: "")
|
||||
]
|
||||
|
||||
|
||||
ForEach(replyTypes, id: \.self) { replyDetails in
|
||||
MessageComposer(text: .constant(""),
|
||||
focused: .constant(false),
|
||||
sendingDisabled: false,
|
||||
mode: .reply(itemID: UUID().uuidString,
|
||||
mode: .reply(itemID: .init(timelineID: UUID().uuidString),
|
||||
replyDetails: replyDetails),
|
||||
sendAction: { },
|
||||
pasteAction: { _ in },
|
||||
|
||||
@@ -71,12 +71,12 @@ struct RoomScreen: View {
|
||||
context.send(viewAction: .handlePasteOrDrop(provider: provider))
|
||||
return true
|
||||
}
|
||||
.confirmationDialog(item: $context.sendFailedConfirmationDialogInfo, titleVisibility: .visible) { item in
|
||||
.confirmationDialog(item: $context.sendFailedConfirmationDialogInfo, titleVisibility: .visible) { info in
|
||||
Button(L10n.screenRoomRetrySendMenuSendAgainAction) {
|
||||
context.send(viewAction: .retrySend(transactionID: item.transactionID))
|
||||
context.send(viewAction: .retrySend(itemID: info.itemID))
|
||||
}
|
||||
Button(L10n.screenRoomRetrySendMenuRemoveAction, role: .destructive) {
|
||||
context.send(viewAction: .cancelSend(transactionID: item.transactionID))
|
||||
context.send(viewAction: .cancelSend(itemID: info.itemID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
|
||||
context.send(viewAction: .displayEmojiPicker(itemID: timelineItem.id))
|
||||
}
|
||||
.onTapGesture {
|
||||
context.send(viewAction: .itemTapped(id: timelineItem.id))
|
||||
context.send(viewAction: .itemTapped(itemID: timelineItem.id))
|
||||
}
|
||||
// We need a tap gesture before this long one so that it doesn't
|
||||
// steal away the gestures from the scroll view
|
||||
@@ -178,7 +178,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
|
||||
if timelineItem.hasFailedToSend {
|
||||
backgroundedLocalizedSendInfo
|
||||
.onTapGesture {
|
||||
context.sendFailedConfirmationDialogInfo = .init(transactionID: timelineItem.properties.transactionID)
|
||||
context.sendFailedConfirmationDialogInfo = .init(itemID: timelineItem.id)
|
||||
}
|
||||
} else {
|
||||
backgroundedLocalizedSendInfo
|
||||
@@ -335,7 +335,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider {
|
||||
|
||||
static var replies: some View {
|
||||
VStack {
|
||||
RoomTimelineItemView(viewModel: .init(item: TextRoomTimelineItem(id: "",
|
||||
RoomTimelineItemView(viewModel: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
||||
timestamp: "10:42",
|
||||
isOutgoing: true,
|
||||
isEditable: false,
|
||||
@@ -344,7 +344,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider {
|
||||
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
|
||||
contentType: .text(.init(body: "Short")))), groupStyle: .single))
|
||||
|
||||
RoomTimelineItemView(viewModel: .init(item: TextRoomTimelineItem(id: "",
|
||||
RoomTimelineItemView(viewModel: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
|
||||
timestamp: "10:42",
|
||||
isOutgoing: true,
|
||||
isEditable: false,
|
||||
|
||||
@@ -67,7 +67,7 @@ struct TimelineItemPlainStylerView<Content: View>: View {
|
||||
context.send(viewAction: .displayEmojiPicker(itemID: timelineItem.id))
|
||||
}
|
||||
.onTapGesture {
|
||||
context.send(viewAction: .itemTapped(id: timelineItem.id))
|
||||
context.send(viewAction: .itemTapped(itemID: timelineItem.id))
|
||||
}
|
||||
// We need a tap gesture before this long one so that it doesn't
|
||||
// steal away the gestures from the scroll view
|
||||
|
||||
@@ -38,7 +38,7 @@ struct TimelineStyler<Content: View>: View {
|
||||
struct TimelineItemStyler_Previews: PreviewProvider {
|
||||
static let viewModel = RoomScreenViewModel.mock
|
||||
|
||||
static let base = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
|
||||
static let base = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
|
||||
|
||||
static let sentNonLast: TextRoomTimelineItem = {
|
||||
var result = base
|
||||
@@ -53,8 +53,8 @@ struct TimelineItemStyler_Previews: PreviewProvider {
|
||||
}()
|
||||
|
||||
static let sendingLast: TextRoomTimelineItem = {
|
||||
let id = viewModel.state.itemIDs.last ?? UUID().uuidString
|
||||
var result = TextRoomTimelineItem(id: id, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
|
||||
let id = viewModel.state.timelineIDs.last ?? UUID().uuidString
|
||||
var result = TextRoomTimelineItem(id: .init(timelineID: id), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
|
||||
result.properties.deliveryStatus = .sending
|
||||
return result
|
||||
}()
|
||||
@@ -66,22 +66,22 @@ struct TimelineItemStyler_Previews: PreviewProvider {
|
||||
}()
|
||||
|
||||
static let sentLast: TextRoomTimelineItem = {
|
||||
let id = viewModel.state.itemIDs.last ?? UUID().uuidString
|
||||
let result = TextRoomTimelineItem(id: id, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
|
||||
let id = viewModel.state.timelineIDs.last ?? UUID().uuidString
|
||||
let result = TextRoomTimelineItem(id: .init(timelineID: id), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"))
|
||||
return result
|
||||
}()
|
||||
|
||||
static let ltrString = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house!"))
|
||||
static let ltrString = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house!"))
|
||||
|
||||
static let rtlString = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת!"))
|
||||
static let rtlString = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת!"))
|
||||
|
||||
static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת! -- house!"))
|
||||
static let ltrStringThatContainsRtl = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת! -- house!"))
|
||||
|
||||
static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת! -- house! -- באמת!"))
|
||||
static let rtlStringThatContainsLtr = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת! -- house! -- באמת!"))
|
||||
|
||||
static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת!"))
|
||||
static let ltrStringThatFinishesInRtl = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "house! -- באמת!"))
|
||||
|
||||
static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: UUID().uuidString, timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת! -- house!"))
|
||||
static let rtlStringThatFinishesInLtr = TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString), timestamp: "Now", isOutgoing: true, isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "באמת! -- house!"))
|
||||
|
||||
static var testView: some View {
|
||||
VStack {
|
||||
|
||||
@@ -23,7 +23,7 @@ struct TimelineItemStatusView: View {
|
||||
@EnvironmentObject private var context: RoomScreenViewModel.Context
|
||||
|
||||
private var isLastOutgoingMessage: Bool {
|
||||
context.viewState.itemIDs.last == timelineItem.id &&
|
||||
context.viewState.timelineIDs.last == timelineItem.id.timelineID &&
|
||||
timelineItem.isOutgoing
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ struct TimelineItemStatusView: View {
|
||||
.foregroundColor(.compound.iconCriticalPrimary)
|
||||
.frame(width: 16, height: 16)
|
||||
.onTapGesture {
|
||||
context.sendFailedConfirmationDialogInfo = .init(transactionID: timelineItem.properties.transactionID)
|
||||
context.sendFailedConfirmationDialogInfo = .init(itemID: timelineItem.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ struct TimelineReactionsView: View {
|
||||
@EnvironmentObject private var context: RoomScreenViewModel.Context
|
||||
@Environment(\.layoutDirection) private var layoutDirection: LayoutDirection
|
||||
|
||||
let itemID: String
|
||||
let itemID: TimelineItemIdentifier
|
||||
let reactions: [AggregatedReaction]
|
||||
@Binding var collapsed: Bool
|
||||
|
||||
@@ -33,7 +33,7 @@ struct TimelineReactionsView: View {
|
||||
CollapsibleFlowLayout(itemSpacing: 4, rowSpacing: 4, collapsed: collapsed, rowsBeforeCollapsible: 2) {
|
||||
ForEach(reactions, id: \.self) { reaction in
|
||||
TimelineReactionButton(itemID: itemID, reaction: reaction) { key in
|
||||
context.send(viewAction: .toggleReaction(key: key, eventID: itemID))
|
||||
context.send(viewAction: .toggleReaction(key: key, itemID: itemID))
|
||||
} showReactionSummary: { key in
|
||||
context.send(viewAction: .reactionSummary(itemID: itemID, key: key))
|
||||
}
|
||||
@@ -93,7 +93,7 @@ struct TimelineCollapseButtonLabel: View {
|
||||
}
|
||||
|
||||
struct TimelineReactionButton: View {
|
||||
let itemID: String
|
||||
let itemID: TimelineItemIdentifier
|
||||
let reaction: AggregatedReaction
|
||||
let toggleReaction: (String) -> Void
|
||||
let showReactionSummary: (String) -> Void
|
||||
@@ -131,11 +131,11 @@ struct TimelineReactionViewPreviewsContainer: View {
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
TimelineReactionsView(itemID: "1", reactions: Array(AggregatedReaction.mockReactions.prefix(3)), collapsed: .constant(true))
|
||||
TimelineReactionsView(itemID: .init(timelineID: "1"), reactions: Array(AggregatedReaction.mockReactions.prefix(3)), collapsed: .constant(true))
|
||||
Divider()
|
||||
TimelineReactionsView(itemID: "2", reactions: AggregatedReaction.mockReactions, collapsed: $collapseState1)
|
||||
TimelineReactionsView(itemID: .init(timelineID: "2"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState1)
|
||||
Divider()
|
||||
TimelineReactionsView(itemID: "3", reactions: AggregatedReaction.mockReactions, collapsed: $collapseState2)
|
||||
TimelineReactionsView(itemID: .init(timelineID: "3"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState2)
|
||||
.environment(\.layoutDirection, .rightToLeft)
|
||||
}
|
||||
.background(Color.red)
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider {
|
||||
ReadReceipt(userID: RoomMemberProxyMock.mockDan.userID, formattedTimestamp: "Way, way before")]
|
||||
|
||||
static func mockTimelineItem(with receipts: [ReadReceipt]) -> TextRoomTimelineItem {
|
||||
TextRoomTimelineItem(id: UUID().uuidString,
|
||||
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: true,
|
||||
isEditable: false, sender: .init(id: UUID().uuidString), content: .init(body: "Test"),
|
||||
|
||||
@@ -44,7 +44,7 @@ struct AudioRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
static var body: some View {
|
||||
AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: UUID().uuidString,
|
||||
AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -71,8 +71,8 @@ private struct CollapsibleRoomTimelineItemDisclosureGroupStyle: DisclosureGroupS
|
||||
|
||||
struct CollapsibleRoomTimelineView_Previews: PreviewProvider {
|
||||
static let item = CollapsibleTimelineItem(items: [
|
||||
SeparatorRoomTimelineItem(id: "First separator", text: "This is a separator"),
|
||||
SeparatorRoomTimelineItem(id: "Second separator", text: "This is another separator")
|
||||
SeparatorRoomTimelineItem(id: .init(timelineID: "First separator"), text: "This is a separator"),
|
||||
SeparatorRoomTimelineItem(id: .init(timelineID: "Second separator"), text: "This is another separator")
|
||||
])
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
@@ -55,7 +55,7 @@ struct EmoteRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
private static func itemWith(text: String, timestamp: String, senderId: String) -> EmoteRoomTimelineItem {
|
||||
EmoteRoomTimelineItem(id: UUID().uuidString,
|
||||
EmoteRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: timestamp,
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ private struct EncryptedHistoryLabelStyle: LabelStyle {
|
||||
|
||||
struct EncryptedHistoryRoomTimelineView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let item = EncryptedHistoryRoomTimelineItem(id: UUID().uuidString)
|
||||
let item = EncryptedHistoryRoomTimelineItem(id: .init(timelineID: UUID().uuidString))
|
||||
EncryptedHistoryRoomTimelineView(timelineItem: item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ struct EncryptedRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> EncryptedRoomTimelineItem {
|
||||
EncryptedRoomTimelineItem(id: UUID().uuidString,
|
||||
EncryptedRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: text,
|
||||
encryptionType: .unknown,
|
||||
timestamp: timestamp,
|
||||
|
||||
@@ -45,21 +45,21 @@ struct FileRoomTimelineView_Previews: PreviewProvider {
|
||||
|
||||
static var body: some View {
|
||||
VStack(spacing: 20.0) {
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: UUID().uuidString,
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "document.pdf", source: nil, thumbnailSource: nil, contentType: nil)))
|
||||
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: UUID().uuidString,
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "document.docx", source: nil, thumbnailSource: nil, contentType: nil)))
|
||||
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: UUID().uuidString,
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -66,21 +66,21 @@ struct ImageRoomTimelineView_Previews: PreviewProvider {
|
||||
|
||||
static var body: some View {
|
||||
VStack(spacing: 20.0) {
|
||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: UUID().uuidString,
|
||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil)))
|
||||
|
||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: UUID().uuidString,
|
||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "Some other image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil)))
|
||||
|
||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: UUID().uuidString,
|
||||
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -91,14 +91,14 @@ struct LocationRoomTimelineView_Previews: PreviewProvider {
|
||||
|
||||
@ViewBuilder
|
||||
static var body: some View {
|
||||
LocationRoomTimelineView(timelineItem: .init(id: UUID().uuidString,
|
||||
LocationRoomTimelineView(timelineItem: .init(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "Fallback geo uri description")))
|
||||
|
||||
LocationRoomTimelineView(timelineItem: .init(id: UUID().uuidString,
|
||||
LocationRoomTimelineView(timelineItem: .init(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -66,7 +66,7 @@ struct NoticeRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
private static func itemWith(text: String, timestamp: String, senderId: String) -> NoticeRoomTimelineItem {
|
||||
NoticeRoomTimelineItem(id: UUID().uuidString,
|
||||
NoticeRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: timestamp,
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -41,8 +41,8 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider {
|
||||
static let item = ReadMarkerRoomTimelineItem()
|
||||
static var previews: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
RoomTimelineItemView(viewModel: .init(type: .separator(.init(id: "Separator", text: "Today")), groupStyle: .single))
|
||||
RoomTimelineItemView(viewModel: .init(type: .text(.init(id: "",
|
||||
RoomTimelineItemView(viewModel: .init(type: .separator(.init(id: .init(timelineID: "Separator"), text: "Today")), groupStyle: .single))
|
||||
RoomTimelineItemView(viewModel: .init(type: .text(.init(id: .init(timelineID: ""),
|
||||
timestamp: "",
|
||||
isOutgoing: true,
|
||||
isEditable: false,
|
||||
@@ -51,8 +51,8 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider {
|
||||
|
||||
ReadMarkerRoomTimelineView(timelineItem: item)
|
||||
|
||||
RoomTimelineItemView(viewModel: .init(type: .separator(.init(id: "Separator", text: "Today")), groupStyle: .single))
|
||||
RoomTimelineItemView(viewModel: .init(type: .text(.init(id: "",
|
||||
RoomTimelineItemView(viewModel: .init(type: .separator(.init(id: .init(timelineID: "Separator"), text: "Today")), groupStyle: .single))
|
||||
RoomTimelineItemView(viewModel: .init(type: .text(.init(id: .init(timelineID: ""),
|
||||
timestamp: "",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -42,7 +42,7 @@ struct RedactedRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
private static func itemWith(text: String, timestamp: String, senderId: String) -> RedactedRoomTimelineItem {
|
||||
RedactedRoomTimelineItem(id: UUID().uuidString,
|
||||
RedactedRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: text,
|
||||
timestamp: timestamp,
|
||||
isOutgoing: false,
|
||||
|
||||
@@ -31,7 +31,7 @@ struct SeparatorRoomTimelineView: View {
|
||||
|
||||
struct SeparatorRoomTimelineView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let item = SeparatorRoomTimelineItem(id: "Separator", text: "This is a separator")
|
||||
let item = SeparatorRoomTimelineItem(id: .init(timelineID: "Separator"), text: "This is a separator")
|
||||
SeparatorRoomTimelineView(timelineItem: item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ struct StateRoomTimelineView_Previews: PreviewProvider {
|
||||
StateRoomTimelineView(timelineItem: item)
|
||||
}
|
||||
|
||||
static let item = StateRoomTimelineItem(id: UUID().uuidString,
|
||||
static let item = StateRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: "Alice joined",
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
|
||||
@@ -58,7 +58,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider {
|
||||
|
||||
static var body: some View {
|
||||
VStack(spacing: 20.0) {
|
||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: UUID().uuidString,
|
||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: "Some image",
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
@@ -66,7 +66,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider {
|
||||
sender: .init(id: "Bob"),
|
||||
imageURL: URL.picturesDirectory))
|
||||
|
||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: UUID().uuidString,
|
||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: "Some other image",
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
@@ -74,7 +74,7 @@ struct StickerRoomTimelineView_Previews: PreviewProvider {
|
||||
sender: .init(id: "Bob"),
|
||||
imageURL: URL.picturesDirectory))
|
||||
|
||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: UUID().uuidString,
|
||||
StickerRoomTimelineView(timelineItem: StickerRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: "Blurhashed image",
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
|
||||
@@ -71,7 +71,7 @@ struct TextRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> TextRoomTimelineItem {
|
||||
TextRoomTimelineItem(id: UUID().uuidString,
|
||||
TextRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: timestamp,
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: isOutgoing,
|
||||
|
||||
@@ -63,7 +63,7 @@ struct UnsupportedRoomTimelineView_Previews: PreviewProvider {
|
||||
}
|
||||
|
||||
private static func itemWith(text: String, timestamp: String, isOutgoing: Bool, senderId: String) -> UnsupportedRoomTimelineItem {
|
||||
UnsupportedRoomTimelineItem(id: UUID().uuidString,
|
||||
UnsupportedRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
body: text,
|
||||
eventType: "Some Event Type",
|
||||
error: "Something went wrong",
|
||||
|
||||
@@ -77,21 +77,21 @@ struct VideoRoomTimelineView_Previews: PreviewProvider {
|
||||
|
||||
static var body: some View {
|
||||
VStack(spacing: 20.0) {
|
||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: UUID().uuidString,
|
||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "Some video", duration: 21, source: nil, thumbnailSource: nil)))
|
||||
|
||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: UUID().uuidString,
|
||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(body: "Some other video", duration: 22, source: nil, thumbnailSource: nil)))
|
||||
|
||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: UUID().uuidString,
|
||||
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .init(timelineID: UUID().uuidString),
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
|
||||
@@ -46,7 +46,7 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
|
||||
case copyPermalink
|
||||
case redact
|
||||
case reply
|
||||
case forward(itemID: String)
|
||||
case forward(itemID: TimelineItemIdentifier)
|
||||
case viewSource
|
||||
case retryDecryption(sessionID: String)
|
||||
case report
|
||||
@@ -188,7 +188,7 @@ public struct TimelineItemMenu: View {
|
||||
private func reactionButton(for emoji: String) -> some View {
|
||||
Button {
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
context.send(viewAction: .toggleReaction(key: emoji, eventID: item.id))
|
||||
context.send(viewAction: .toggleReaction(key: emoji, itemID: item.id))
|
||||
} label: {
|
||||
Text(emoji)
|
||||
.padding(8.0)
|
||||
|
||||
@@ -72,7 +72,7 @@ class TimelineTableViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
var contextMenuActionProvider: (@MainActor (_ itemId: String) -> TimelineItemMenuActions?)?
|
||||
var contextMenuActionProvider: (@MainActor (_ itemID: TimelineItemIdentifier) -> TimelineItemMenuActions?)?
|
||||
|
||||
@Binding private var scrollToBottomButtonVisible: Bool
|
||||
|
||||
@@ -214,10 +214,10 @@ class TimelineTableViewController: UIViewController {
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.environmentObject(coordinator.context) // Attempted fix at a crash in TimelineItemContextMenu
|
||||
.onAppear {
|
||||
coordinator.send(viewAction: .itemAppeared(id: id))
|
||||
coordinator.send(viewAction: .itemAppeared(itemID: viewModel.id))
|
||||
}
|
||||
.onDisappear {
|
||||
coordinator.send(viewAction: .itemDisappeared(id: id))
|
||||
coordinator.send(viewAction: .itemDisappeared(itemID: viewModel.id))
|
||||
}
|
||||
.environment(\.openURL, OpenURLAction { url in
|
||||
coordinator.send(viewAction: .linkClicked(url: url))
|
||||
@@ -231,7 +231,7 @@ class TimelineTableViewController: UIViewController {
|
||||
return cell
|
||||
}
|
||||
|
||||
dataSource?.defaultRowAnimation = .fade
|
||||
// dataSource?.defaultRowAnimation = .automatic
|
||||
|
||||
tableView.delegate = self
|
||||
}
|
||||
@@ -248,6 +248,8 @@ class TimelineTableViewController: UIViewController {
|
||||
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, String>()
|
||||
snapshot.appendSections([.main])
|
||||
snapshot.appendItems(timelineItemsIDs)
|
||||
|
||||
MXLog.verbose("DIFF: \(snapshot.itemIdentifiers.difference(from: dataSource.snapshot().itemIdentifiers))")
|
||||
dataSource.apply(snapshot, animatingDifferences: false)
|
||||
|
||||
// Probably redundant now we observe content size changes…
|
||||
@@ -421,7 +423,7 @@ extension TimelineTableViewController {
|
||||
private extension UITableView {
|
||||
/// Returns the frame of the cell for a particular timeline item.
|
||||
func cellFrame(for id: String) -> CGRect? {
|
||||
guard let timelineCell = visibleCells.last(where: { ($0 as? TimelineItemCell)?.item?.id == id }) else {
|
||||
guard let timelineCell = visibleCells.last(where: { ($0 as? TimelineItemCell)?.item?.id.timelineID == id }) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user