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