Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ public struct WireCellsFactory {
)
}

public func makeDeleteNodesUseCase() -> any WireCellsDeleteNodesUseCaseProtocol {
WireCellsDeleteNodesUseCase(
repository: nodesAPI,
fileCache: fileCache,
localAssetStore: localAssetStore
)
}

}

public extension WireCellsFactory {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

public import Foundation

public protocol WireCellsDeleteNodesUseCaseProtocol: Sendable {

func invoke(nodeIDs: [UUID]) async throws

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ package enum WireCellsDeleteNodesError: Error {
}

/// Deletes `WireCellNodes`s from both the server and locally cached data.
package struct WireCellsDeleteNodesUseCase: Sendable {
package struct WireCellsDeleteNodesUseCase: WireCellsDeleteNodesUseCaseProtocol {

private let repository: any WireCellsNodesRepositoryProtocol
private let fileCache: any FileCache
Expand Down
18 changes: 18 additions & 0 deletions wire-ios/Tests/Sourcery/generated/AutoMockable.generated.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ final class ConversationContentViewControllerTests: XCTestCase, CoreDataFixtureT
message: mockMessage,
sourceView: view,
userSession: userSession
) { _ in })
) { _, _ in })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ extension CollectionsViewController: CollectionCellDelegate {
forMessage: message,
source: source,
userSession: userSession
) { [weak self] deleted in
) { [weak self] deleted, _ in
guard deleted else { return }
_ = self?.navigationController?.popViewController(animated: true)
self?.refetchCollection()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ final class ConversationMultipartMessageCell: UIView, ConversationMessageCell {
weak var delegate: ConversationMessageCellDelegate?
weak var message: ZMConversationMessage?
weak var actionController: ConversationMessageActionController?

var isSelected: Bool = false

override init(frame: CGRect) {
Expand Down Expand Up @@ -78,6 +77,7 @@ final class ConversationMultipartMessageCell: UIView, ConversationMessageCell {
with object: Configuration,
animated: Bool
) {

let attachments = object.attachments.map {
WireCellsMessageAttachment(
nodeID: $0.nodeID,
Expand Down Expand Up @@ -134,6 +134,7 @@ final class ConversationMultipartMessageCellDescription: ConversationMessageCell

let accessibilityIdentifier: String? = nil
let accessibilityLabel: String? = nil
var supportsActions: Bool = true

init(
multipartMessage: MultipartMessageData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
bottomAnchor.constraint(equalTo: attachmentView.bottomAnchor),
widthConstraint
])

Check warning on line 99 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/Content/Text/ConversationLinkAttachmentCell.swift

View workflow job for this annotation

GitHub Actions / Test Results

'shared()' is deprecated: This shared instance has been deprecated. Don't use it.

'shared()' is deprecated: This shared instance has been deprecated. Don't use it.
if ZMUserSession.shared()?.isChatBubbleSimpleEnabled ?? false {
NSLayoutConstraint.activate(chatBubbleConstraints)
} else {
Expand Down Expand Up @@ -180,14 +180,20 @@
weak var actionController: ConversationMessageActionController?

let supportsActions: Bool = true
let containsHighlightableContent: Bool = true

Check warning on line 183 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/Content/Text/ConversationLinkAttachmentCell.swift

View workflow job for this annotation

GitHub Actions / Test Results

'shared()' is deprecated: This shared instance has been deprecated. Don't use it.

'shared()' is deprecated: This shared instance has been deprecated. Don't use it.
lazy var shouldAlignMessageContentForBubbles: Bool = ZMUserSession.shared()?.isChatBubbleSimpleEnabled ?? false

let accessibilityIdentifier: String? = nil
let accessibilityLabel: String? = nil

init(attachment: LinkAttachment, thumbnailResource: WireImageResource?) {
self.configuration = View.Configuration(attachment: attachment, thumbnailResource: thumbnailResource)
init(
attachment: LinkAttachment,
thumbnailResource: WireImageResource?
) {
self.configuration = View.Configuration(
attachment: attachment,
thumbnailResource: thumbnailResource
)
self.actionController = nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
let isObfuscated: Bool
let userSession: UserSession?

init(attributedText: NSAttributedString, isObfuscated: Bool, userSession: UserSession? = nil) {
init(
attributedText: NSAttributedString,
isObfuscated: Bool,
userSession: UserSession? = nil
) {
self.attributedText = attributedText
self.isObfuscated = isObfuscated
self.userSession = userSession
Expand Down Expand Up @@ -219,7 +223,7 @@
return true
}

func textViewDidLongPress(_ textView: LinkInteractionTextView) {

Check warning on line 226 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/Content/Text/ConversationTextMessageCell.swift

View workflow job for this annotation

GitHub Actions / Test Results

'UIMenuController' was deprecated in iOS 16.0: UIMenuController is deprecated. Use UIEditMenuInteraction instead.

'UIMenuController' was deprecated in iOS 16.0: UIMenuController is deprecated. Use UIEditMenuInteraction instead.
if !UIMenuController.shared.isMenuVisible {
if !Settings.isClipboardEnabled {
menuPresenter?.showSecuredMenu()
Expand Down Expand Up @@ -263,11 +267,15 @@
let accessibilityIdentifier: String? = nil
let accessibilityLabel: String? = nil

init(attributedString: NSAttributedString, isObfuscated: Bool, userSession: UserSession?) {
init(
attributedString: NSAttributedString,
isObfuscated: Bool,
userSession: UserSession?
) {
self.configuration = View.Configuration(
attributedText: attributedString,
isObfuscated: isObfuscated,
userSession: userSession
userSession: userSession,
)
}
}
Expand Down Expand Up @@ -366,7 +374,10 @@
cells.append(AnyConversationMessageCellDescription(attachmentCell))
} else if textMessageData.linkPreview != nil {
// Link Preview
let linkPreviewCell = ConversationLinkPreviewArticleCellDescription(message: message, data: textMessageData)
let linkPreviewCell = ConversationLinkPreviewArticleCellDescription(
message: message,
data: textMessageData
)
cells.append(AnyConversationMessageCellDescription(linkPreviewCell))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,12 @@
if shouldCollapseCell() {
return addCollapsedCell()
}

Check warning on line 260 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift

View workflow job for this annotation

GitHub Actions / Test Results

Initialization of immutable value 'attachments' was never used; consider replacing with assignment to '_' or removing it

Initialization of immutable value 'attachments' was never used; consider replacing with assignment to '_' or removing it
let attachments = message.multipartMessageData?.attachments ?? []
let multipartMessageCellDescription = ConversationMultipartMessageCellDescription(
multipartMessage: message.multipartMessageData!,
wireCellsFactory: wireCellsFactory
)

return [AnyConversationMessageCellDescription(multipartMessageCellDescription)]
}

Expand Down Expand Up @@ -319,6 +319,9 @@
if shouldCollapseCell() {
return addCollapsedCell()
}

Check warning on line 322 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift

View workflow job for this annotation

GitHub Actions / Test Results

Initialization of immutable value 'attachments' was never used; consider replacing with assignment to '_' or removing it

Initialization of immutable value 'attachments' was never used; consider replacing with assignment to '_' or removing it
let attachments = message.multipartMessageData?.attachments ?? []

return ConversationTextMessageCellDescription
.cells(
for: message,
Expand Down Expand Up @@ -384,7 +387,8 @@
guard let compositeMessage = message as? ConversationCompositeMessage else { return [] }

var cells: [AnyConversationMessageCellDescription] = []

Check warning on line 390 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift

View workflow job for this annotation

GitHub Actions / Test Results

Initialization of immutable value 'attachments' was never used; consider replacing with assignment to '_' or removing it

Initialization of immutable value 'attachments' was never used; consider replacing with assignment to '_' or removing it
let attachments = message.multipartMessageData?.attachments ?? []
compositeMessage.compositeMessageData?.items.forEach { item in
switch item {

Expand Down Expand Up @@ -645,7 +649,7 @@
let observer = UserChangeInfo.add(observer: self, for: sender, in: userSession)!
changeObservers.append(observer)
}

Check warning on line 652 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/Cells/ConfigurationMessageCell/ConversationMessageSectionController.swift

View workflow job for this annotation

GitHub Actions / Test Results

'users' is deprecated: Use `userTypes` instead

'users' is deprecated: Use `userTypes` instead
if let users = message.systemMessageData?.users {
for user in users where user.remoteIdentifier != (message.senderUser as? ZMUser)?.remoteIdentifier {
if let observer = UserChangeInfo.add(observer: self, for: user, in: userSession) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
userSession.enqueue {
WireLogger.messaging.info(
"cancel message",
attributes: [

Check warning on line 74 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationContentViewController+MessageAction.swift

View workflow job for this annotation

GitHub Actions / Test Results

'conversation' is deprecated: Use `conversationLike` instead

'conversation' is deprecated: Use `conversationLike` instead
LogAttributesKey.conversationId: message.conversation?.qualifiedID?
.safeForLoggingDescription ?? "<nil>"
], .safePublic
Expand All @@ -83,7 +83,7 @@
userSession.enqueue {
WireLogger.messaging.info(
"resend message",
attributes: [

Check warning on line 86 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationContentViewController+MessageAction.swift

View workflow job for this annotation

GitHub Actions / Test Results

'conversation' is deprecated: Use `conversationLike` instead

'conversation' is deprecated: Use `conversationLike` instead
LogAttributesKey.conversationId: message.conversation?.qualifiedID?
.safeForLoggingDescription ?? "<nil>"
], .safePublic
Expand All @@ -93,15 +93,26 @@
}
case .delete:
assert(message.canBeDeleted)
let attachments = message.multipartMessageData?.attachments

deletionDialogPresenter = DeletionDialogPresenter(sourceViewController: presentedViewController ?? self)
deletionDialogPresenter?.presentDeletionAlertController(
forMessage: message,
source: view,
userSession: userSession
) { deleted in
) { [weak self] deleted, deletionType in
guard let self else { return }

if deleted {
self.presentedViewController?.dismiss(animated: true)
presentedViewController?.dismiss(animated: true)
if let attachments, let deletionType {
delegate?.conversationContentViewController(
self,
didDeleteMultipartMessage: message,
withAttachments: attachments,
deletionType: deletionType
)
}
}
}
case .present:
Expand Down Expand Up @@ -235,7 +246,7 @@
}

func didReceiveDigitalSignature(_ cmsFileMetadata: ZMFileMetadata) {
dismissDigitalSignatureVerification { [weak self] in

Check warning on line 249 in wire-ios/Wire-iOS/Sources/UserInterface/Conversation/Content/ConversationContentViewController+MessageAction.swift

View workflow job for this annotation

GitHub Actions / Test Results

'shared()' is deprecated: This shared instance has been deprecated. Don't use it.

'shared()' is deprecated: This shared instance has been deprecated. Don't use it.
ZMUserSession.shared()?.perform {
do {
try self?.conversation.appendFile(with: cmsFileMetadata)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ final class DeletionDialogPresenter: NSObject {
message: ZMConversationMessage,
sourceView: UIView,
userSession: UserSession,
completion: @escaping (_ succeeded: Bool) -> Void
completion: @escaping (_ succeeded: Bool, DeletionType?) -> Void
) -> UIAlertController {
let alert = UIAlertController.forMessageDeletion(with: message.deletionConfiguration) { action, _ in

Expand All @@ -78,10 +78,10 @@ final class DeletionDialogPresenter: NSObject {
ZMMessage.deleteForEveryone(message)
}
} completionHandler: {
completion(true)
completion(true, type)
}
} else {
completion(false)
completion(false, nil)
}
}

Expand Down Expand Up @@ -116,7 +116,7 @@ final class DeletionDialogPresenter: NSObject {
forMessage message: ZMConversationMessage,
source: UIView,
userSession: UserSession,
completion: @escaping (_ succeeded: Bool) -> Void
completion: @escaping (_ succeeded: Bool, DeletionType?) -> Void
) {
guard !message.hasBeenDeleted else { return }

Expand All @@ -130,14 +130,15 @@ final class DeletionDialogPresenter: NSObject {
}
}

private enum AlertAction {
enum DeletionType {
case local
case everywhere
}

enum DeletionType {
case local
case everywhere
}
private enum AlertAction {

case delete(DeletionType), cancel
case delete(DeletionType)
case cancel
}

// Used to enforce only valid configurations can be shown.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,11 @@ protocol ConversationContentViewControllerDelegate: AnyObject {
actionController: ConversationMessageActionController,
popoverPresentationInfo: (sourceView: UIView, frame: CGRect)?
)

func conversationContentViewController(
_ controller: ConversationContentViewController,
didDeleteMultipartMessage message: ZMConversationMessage,
withAttachments attachments: [MultipartMessageData.Attachment],
deletionType: DeletionType
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,36 @@ extension ConversationViewController: ConversationContentViewControllerDelegate
}
}

func conversationContentViewController(
_ controller: ConversationContentViewController,
didDeleteMultipartMessage message: any ZMConversationMessage,
withAttachments attachments: [MultipartMessageData.Attachment],
deletionType: DeletionType
) {
switch deletionType {
case .everywhere:
Task {
let deleteNodesUseCase = wireCellsFactory.makeDeleteNodesUseCase()
do {
try await deleteNodesUseCase.invoke(nodeIDs: attachments.map(\.nodeID))
WireLogger.conversation.info(
"Deleted files for message",
attributes: [.nonce: message.nonce?.uuidString]
)
} catch {
WireLogger.conversation
.error(
"Unable to delete files: \(String(describing: error))",
attributes: [.nonce: message.nonce?.uuidString], .safePublic
)
}
}
case .local:
// no op, related files will still show up for self user (as aligned other clients)
break
}
}

}

extension ConversationViewController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ protocol WireCellsFactoryProtocol {
func makeClearPublishedDraftsUseCase(cellName: String) -> WireCellsClearPublishedDraftsUseCaseProtocol
func makeDeleteDraftUseCase(cellName: String) -> WireCellsDeleteDraftUseCaseProtocol
func makeRetryUploadDraftUseCase(cellName: String) -> WireCellsRetryUploadDraftUseCaseProtocol
func makeDeleteNodesUseCase() -> WireCellsDeleteNodesUseCaseProtocol
@MainActor
func makeFilesView(cellName: String, isCellsStatePending: Bool, nodeIDs: [UUID]) -> UIViewController
@MainActor
Expand Down
Loading