mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Filter out some actions for failed local echoes (#1184)
* done * pr suggestion
This commit is contained in:
@@ -354,16 +354,16 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
var actions: [TimelineItemMenuAction] = [
|
||||
.reply
|
||||
]
|
||||
|
||||
if timelineItem is EventBasedMessageTimelineItemProtocol {
|
||||
|
||||
if item.isMessage {
|
||||
actions.append(.forward(itemID: itemId))
|
||||
}
|
||||
|
||||
|
||||
if item.isEditable {
|
||||
actions.append(.edit)
|
||||
}
|
||||
|
||||
if timelineItem is EventBasedMessageTimelineItemProtocol {
|
||||
|
||||
if item.isMessage {
|
||||
actions.append(.copy)
|
||||
}
|
||||
|
||||
@@ -381,7 +381,15 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
case let .megolmV1AesSha2(sessionID) = item.encryptionType {
|
||||
debugActions.append(.retryDecryption(sessionID: sessionID))
|
||||
}
|
||||
|
||||
|
||||
if item.hasFailedToSend {
|
||||
actions = actions.filter(\.canAppearInFailedEcho)
|
||||
}
|
||||
|
||||
if item.isRedacted {
|
||||
actions = actions.filter(\.canAppearInRedacted)
|
||||
}
|
||||
|
||||
return .init(actions: actions, debugActions: debugActions)
|
||||
}
|
||||
|
||||
@@ -416,7 +424,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
case .redact:
|
||||
Task {
|
||||
await timelineController.redact(itemID)
|
||||
if eventTimelineItem.hasFailedToSend,
|
||||
let transactionID = eventTimelineItem.properties.transactionID {
|
||||
await timelineController.cancelSend(transactionID)
|
||||
} else {
|
||||
await timelineController.redact(itemID)
|
||||
}
|
||||
}
|
||||
case .reply:
|
||||
state.bindings.composerFocused = true
|
||||
|
||||
@@ -151,7 +151,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
|
||||
|
||||
@ViewBuilder
|
||||
var interactiveLocalizedSendInfo: some View {
|
||||
if timelineItem.properties.deliveryStatus == .sendingFailed {
|
||||
if timelineItem.hasFailedToSend {
|
||||
backgroundedLocalizedSendInfo
|
||||
.onTapGesture {
|
||||
context.sendFailedConfirmationDialogInfo = .init(transactionID: timelineItem.properties.transactionID)
|
||||
@@ -186,12 +186,12 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
|
||||
Text(timelineItem.timestamp)
|
||||
}
|
||||
|
||||
if timelineItem.properties.deliveryStatus == .sendingFailed {
|
||||
if timelineItem.hasFailedToSend {
|
||||
Image(systemName: "exclamationmark.circle.fill")
|
||||
}
|
||||
}
|
||||
.font(.compound.bodyXS)
|
||||
.foregroundColor(timelineItem.properties.deliveryStatus == .sendingFailed ? .compound.textCriticalPrimary : .compound.textSecondary)
|
||||
.foregroundColor(timelineItem.hasFailedToSend ? .compound.textCriticalPrimary : .compound.textSecondary)
|
||||
.padding(.bottom, shouldFillBubble ? 0 : -4)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ extension TextBasedRoomTimelineViewProtocol {
|
||||
}
|
||||
|
||||
// To account for the extra spacing created by the alert icon
|
||||
if timelineItem.properties.deliveryStatus == .sendingFailed {
|
||||
if timelineItem.hasFailedToSend {
|
||||
whiteSpaces += 3
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,24 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var canAppearInFailedEcho: Bool {
|
||||
switch self {
|
||||
case .copy, .redact, .viewSource:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var canAppearInRedacted: Bool {
|
||||
switch self {
|
||||
case .viewSource:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct TimelineItemMenu: View {
|
||||
@@ -70,17 +88,21 @@ public struct TimelineItemMenu: View {
|
||||
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 0.0) {
|
||||
reactionsSection
|
||||
.padding(.top, 4.0)
|
||||
.padding(.bottom, 8.0)
|
||||
|
||||
Divider()
|
||||
.background(Color.compound.bgSubtlePrimary)
|
||||
|
||||
viewsForActions(actions.actions)
|
||||
|
||||
Divider()
|
||||
.background(Color.compound.bgSubtlePrimary)
|
||||
if !item.isRedacted, !item.hasFailedToSend {
|
||||
reactionsSection
|
||||
.padding(.top, 4.0)
|
||||
.padding(.bottom, 8.0)
|
||||
|
||||
Divider()
|
||||
.background(Color.compound.bgSubtlePrimary)
|
||||
}
|
||||
|
||||
if !actions.actions.isEmpty {
|
||||
viewsForActions(actions.actions)
|
||||
|
||||
Divider()
|
||||
.background(Color.compound.bgSubtlePrimary)
|
||||
}
|
||||
|
||||
viewsForActions(actions.debugActions)
|
||||
}
|
||||
@@ -238,7 +260,7 @@ public struct TimelineItemMenu: View {
|
||||
|
||||
struct TimelineItemMenu_Previews: PreviewProvider {
|
||||
static let viewModel = RoomScreenViewModel.mock
|
||||
|
||||
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
if let item = RoomTimelineItemFixtures.singleMessageChunk.first as? EventBasedTimelineItemProtocol,
|
||||
|
||||
@@ -64,6 +64,8 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
func editMessage(_ newMessage: String, original itemID: String) async { }
|
||||
|
||||
func redact(_ itemID: String) async { }
|
||||
|
||||
func cancelSend(_ transactionID: String) async { }
|
||||
|
||||
func debugInfo(for itemID: String) -> TimelineItemDebugInfo {
|
||||
.init(model: "Mock debug description", originalJSON: nil, latestEditJSON: nil)
|
||||
|
||||
@@ -185,6 +185,11 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
MXLog.error("Failed redacting message with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func cancelSend(_ transactionID: String) async {
|
||||
MXLog.info("Cancelling send in \(roomID)")
|
||||
await roomProxy.cancelSend(transactionID: transactionID)
|
||||
}
|
||||
|
||||
// Handle this parallel to the timeline items so we're not forced
|
||||
// to bundle the Rust side objects within them
|
||||
|
||||
+2
@@ -57,6 +57,8 @@ protocol RoomTimelineControllerProtocol {
|
||||
func toggleReaction(_ reaction: String, to itemID: String) async
|
||||
|
||||
func redact(_ itemID: String) async
|
||||
|
||||
func cancelSend(_ transactionID: String) async
|
||||
|
||||
func debugInfo(for itemID: String) -> TimelineItemDebugInfo
|
||||
|
||||
|
||||
@@ -33,4 +33,16 @@ extension EventBasedTimelineItemProtocol {
|
||||
var description: String {
|
||||
"\(String(describing: Self.self)): id: \(id), timestamp: \(timestamp), isOutgoing: \(isOutgoing), properties: \(properties)"
|
||||
}
|
||||
|
||||
var hasFailedToSend: Bool {
|
||||
properties.deliveryStatus == .sendingFailed
|
||||
}
|
||||
|
||||
var isMessage: Bool {
|
||||
self is EventBasedMessageTimelineItemProtocol
|
||||
}
|
||||
|
||||
var isRedacted: Bool {
|
||||
self is RedactedRoomTimelineItem
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Filter out some message actions and reactions for failed local echoes and redacted messages.
|
||||
Reference in New Issue
Block a user