From dae8f93b40f51564cb744cf917c6b5289c050a7b Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:24:28 +0000 Subject: [PATCH] Revert decryption banner & try fix context menu crash. (#525) --- .../en.lproj/Untranslated.strings | 2 + .../Generated/Strings+Untranslated.swift | 2 + .../Screens/RoomScreen/RoomScreenModels.swift | 2 - .../RoomScreen/RoomScreenViewModel.swift | 42 +++++------------- .../Screens/RoomScreen/View/RoomScreen.swift | 43 +------------------ .../Style/TimelineItemBubbledStylerView.swift | 4 +- .../View/TimelineItemContextMenu.swift | 5 +++ .../RoomTimelineController.swift | 7 +-- .../RoomTimelineControllerProtocol.swift | 1 - 9 files changed, 23 insertions(+), 85 deletions(-) diff --git a/ElementX/Resources/Localizations/en.lproj/Untranslated.strings b/ElementX/Resources/Localizations/en.lproj/Untranslated.strings index deda96cd61..6f5fdaebc6 100644 --- a/ElementX/Resources/Localizations/en.lproj/Untranslated.strings +++ b/ElementX/Resources/Localizations/en.lproj/Untranslated.strings @@ -26,6 +26,8 @@ "room_timeline_syncing" = "Syncing"; "room_timeline_unable_to_decrypt" = "Unable to decrypt"; +"room_timeline_context_menu_retry_decryption" = "Retry decryption"; + "room_timeline_item_unsupported" = "Unsupported event"; "room_timeline_image_gif" = "GIF"; "room_timeline_read_marker_title" = "New"; diff --git a/ElementX/Sources/Generated/Strings+Untranslated.swift b/ElementX/Sources/Generated/Strings+Untranslated.swift index e04e80916d..c23ebae7ea 100644 --- a/ElementX/Sources/Generated/Strings+Untranslated.swift +++ b/ElementX/Sources/Generated/Strings+Untranslated.swift @@ -98,6 +98,8 @@ extension ElementL10n { public static let roomDetailsTitle = ElementL10n.tr("Untranslated", "room_details_title") /// Failed loading messages public static let roomTimelineBackpaginationFailure = ElementL10n.tr("Untranslated", "room_timeline_backpagination_failure") + /// Retry decryption + public static let roomTimelineContextMenuRetryDecryption = ElementL10n.tr("Untranslated", "room_timeline_context_menu_retry_decryption") /// Editing public static let roomTimelineEditing = ElementL10n.tr("Untranslated", "room_timeline_editing") /// GIF diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift index 319240b5d9..39f1984902 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift @@ -53,7 +53,6 @@ enum RoomScreenViewAction { case cancelEdit /// Mark the entire room as read - this is heavy handed as a starting point for now. case markRoomAsRead - case retryDecryption case contextMenuAction(itemID: String, action: TimelineItemContextMenuAction) } @@ -64,7 +63,6 @@ struct RoomScreenViewState: BindableState { var items: [RoomTimelineViewProvider] = [] var canBackPaginate = true var isBackPaginating = false - var showEncryptionBanner = false var showLoading = false var bindings: RoomScreenViewStateBindings diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 164b04bf4e..e26534de4a 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -29,7 +29,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol private let timelineController: RoomTimelineControllerProtocol private let timelineViewFactory: RoomTimelineViewFactoryProtocol - // swiftlint:disable:next cyclomatic_complexity init(timelineController: RoomTimelineControllerProtocol, timelineViewFactory: RoomTimelineViewFactoryProtocol, mediaProvider: MediaProviderProtocol, @@ -67,10 +66,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol if self.state.isBackPaginating != isBackPaginating { self.state.isBackPaginating = isBackPaginating } - case .hasEncryptedItems(let hasEncryptedItems): - if self.state.showEncryptionBanner != hasEncryptedItems { - self.state.showEncryptionBanner = hasEncryptedItems - } } } .store(in: &cancellables) @@ -118,8 +113,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol state.bindings.composerText = "" case .markRoomAsRead: await markRoomAsRead() - case .retryDecryption: - retryDecryption() case .contextMenuAction(let itemID, let action): processContentMenuAction(action, itemID: itemID) } @@ -189,19 +182,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol } } - /// Retry decrypting any encrypted items in the timeline. - private func retryDecryption() { - Task { - let firstEncryptedItem = state.items.first { $0.sessionID != nil } - - if let sessionID = firstEncryptedItem?.sessionID { - // Request for the first encrypted item to be decrypted as the SDK - // will continue to decrypt any following items automatically. - await timelineController.retryDecryption(for: sessionID) - } - } - } - private func displayError(_ type: RoomScreenErrorType) { switch type { case .alert(let message): @@ -244,7 +224,12 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol actions.append(.redact) } - let debugActions: [TimelineItemContextMenuAction] = [.viewSource] + var debugActions: [TimelineItemContextMenuAction] = [.viewSource] + + if let item = timelineItem as? EncryptedRoomTimelineItem, + case let .megolmV1AesSha2(sessionID) = item.encryptionType { + debugActions.append(.retryDecryption(sessionID: sessionID)) + } return .init(actions: actions, debugActions: debugActions) } @@ -286,6 +271,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol let debugDescription = timelineController.debugDescription(for: item.id) MXLog.info(debugDescription) state.bindings.debugInfo = .init(title: "Timeline item", content: debugDescription) + case .retryDecryption(let sessionID): + Task { + await timelineController.retryDecryption(for: sessionID) + } } if action.switchToDefaultComposer { @@ -302,14 +291,3 @@ extension RoomScreenViewModel { mediaProvider: MockMediaProvider(), roomName: "Preview room") } - -private extension RoomTimelineViewProvider { - /// The item's session ID if it was unable to decrypt and uses megolm. - /// This will be nil for items that have already been decrypted. - var sessionID: String? { - guard case let .encrypted(item) = self, - case let .megolmV1AesSha2(sessionID) = item.encryptionType - else { return nil } - return sessionID - } -} diff --git a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift index da6d632221..c98a21d450 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift @@ -24,8 +24,6 @@ struct RoomScreen: View { var body: some View { timeline .background(Color.element.background.ignoresSafeArea()) // Kills the toolbar translucency. - .overlay(alignment: .top) { encryptionBanner } // Overlay for now, safeAreaInset breaks timeline scroll offset. - .animation(.spring(), value: context.viewState.showEncryptionBanner) .safeAreaInset(edge: .bottom, spacing: 0) { messageComposer } .navigationBarTitleDisplayMode(.inline) .toolbar { toolbar } @@ -51,44 +49,6 @@ struct RoomScreen: View { .overlay(alignment: .bottomTrailing) { scrollToBottomButton } } - @ViewBuilder - var encryptionBanner: some View { - if context.viewState.showEncryptionBanner { - VStack(alignment: .leading, spacing: 4) { - Label { - Text("Unable to decrypt all messages") - .foregroundColor(.element.primaryContent) - } icon: { - Image(systemName: "lock.shield") - .foregroundColor(.element.background) - .padding(4) - .background(Color.element.tertiaryContent) - .cornerRadius(5) - } - .font(.element.bodyBold) - - Text("Accessing your encrypted message history is not fully supported yet.") - .font(.element.subheadline) - .foregroundColor(.element.secondaryContent) - .padding(.bottom, 8) - - Button(ElementL10n.globalRetry) { - context.send(viewAction: .retryDecryption) - } - .buttonStyle(.elementCapsuleProminent) - } - .padding(.horizontal, 16) - .padding(.vertical, 12) - .background { - RoundedRectangle(cornerRadius: 8) - .fill(Color.element.system) - } - .padding([.horizontal, .top], 16) - .background(Color.element.background) - .transition(.move(edge: .top).combined(with: .opacity)) - } - } - var messageComposer: some View { MessageComposer(text: $context.composerText, focused: $context.composerFocused, @@ -150,8 +110,7 @@ struct RoomScreen_Previews: PreviewProvider { roomName: "Preview room") NavigationView { - RoomScreen(context: viewModel.context).encryptionBanner - .padding() + RoomScreen(context: viewModel.context) } } } diff --git a/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemBubbledStylerView.swift b/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemBubbledStylerView.swift index 97063fb039..46bfac1eb8 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemBubbledStylerView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemBubbledStylerView.swift @@ -91,8 +91,8 @@ struct TimelineItemBubbledStylerView: View { var messageBubble: some View { styledContent .contentShape(.contextMenuPreview, RoundedCornerShape(radius: cornerRadius, corners: timelineItem.roundedCorners)) // Rounded corners for the context menu animation. - .contextMenu { [weak context] in - context?.viewState.contextMenuActionProvider?(timelineItem.id).map { actions in + .contextMenu { + context.viewState.contextMenuActionProvider?(timelineItem.id).map { actions in TimelineItemContextMenu(itemID: timelineItem.id, contextMenuActions: actions) } } diff --git a/ElementX/Sources/Screens/RoomScreen/View/TimelineItemContextMenu.swift b/ElementX/Sources/Screens/RoomScreen/View/TimelineItemContextMenu.swift index 9ad36fc0d9..13bceb7e3d 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/TimelineItemContextMenu.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/TimelineItemContextMenu.swift @@ -39,6 +39,7 @@ enum TimelineItemContextMenuAction: Identifiable, Hashable { case redact case reply case viewSource + case retryDecryption(sessionID: String) var id: Self { self } @@ -102,6 +103,10 @@ public struct TimelineItemContextMenu: View { Button { send(action) } label: { Label(ElementL10n.viewSource, systemImage: "doc.text.below.ecg") } + case .retryDecryption: + Button { send(action) } label: { + Label(ElementL10n.roomTimelineContextMenuRetryDecryption, systemImage: "arrow.down.message") + } } } } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index a6bf4e73e0..c26fe26cb3 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -218,12 +218,11 @@ class RoomTimelineController: RoomTimelineControllerProtocol { updateTimelineItems() } - // swiftlint:disable:next cyclomatic_complexity function_body_length + // swiftlint:disable:next cyclomatic_complexity private func updateTimelineItems() { var newTimelineItems = [RoomTimelineItemProtocol]() var canBackPaginate = true var isBackPaginating = false - var hasEncryptedItems = false var createdIdentifiers = [String: Bool]() @@ -244,9 +243,6 @@ class RoomTimelineController: RoomTimelineControllerProtocol { if createdIdentifiers[timelineItem.id] == nil { newTimelineItems.append(timelineItem) createdIdentifiers[timelineItem.id] = true - if timelineItem is EncryptedRoomTimelineItem { - hasEncryptedItems = true - } } else { MXLog.error("Found duplicated timeline item, ignoring") } @@ -284,7 +280,6 @@ class RoomTimelineController: RoomTimelineControllerProtocol { callbacks.send(.updatedTimelineItems) callbacks.send(.canBackPaginate(canBackPaginate)) callbacks.send(.isBackPaginating(isBackPaginating)) - callbacks.send(.hasEncryptedItems(hasEncryptedItems)) } private func computeGroupState(for itemProxy: TimelineItemProxy, diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift index 2f01e2c991..404becf36b 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineControllerProtocol.swift @@ -23,7 +23,6 @@ enum RoomTimelineControllerCallback { case updatedTimelineItem(_ itemId: String) case canBackPaginate(Bool) case isBackPaginating(Bool) - case hasEncryptedItems(Bool) } enum RoomTimelineControllerAction {