From 3f5bc18f6b99c9aa32b4846ebdc1fb842c512230 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 7 Dec 2020 15:11:49 +1100 Subject: [PATCH] Fix remaining TODOs --- .../ConversationViewController.m | 36 ++++++++------ .../Control Messages/ClosedGroupUpdate.swift | 20 +++++++- .../ExpirationTimerUpdate.swift | 9 ++++ .../Control Messages/ReadReceipt.swift | 9 ++++ .../Control Messages/TypingIndicator.swift | 18 ++++++- .../Signal/TSOutgoingMessage+Conversion.swift | 21 +++++++++ .../VisibleMessage+LinkPreview.swift | 11 +++++ .../VisibleMessage+Profile.swift | 11 +++++ .../VisibleMessage+Quote.swift | 15 +++++- .../Visible Messages/VisibleMessage.swift | 14 ++++++ .../OWSLinkPreview+Conversion.swift | 5 ++ .../Sending & Receiving/MessageSender.swift | 22 ++++++++- .../Quotes/TSQuotedMessage+Conversion.swift | 13 +++++ .../MessageSender+Convenience.swift | 11 ++++- .../UI/SharingThreadPickerViewController.m | 47 +++++++++---------- 15 files changed, 216 insertions(+), 46 deletions(-) diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index e23512245..e0560412d 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -1454,9 +1454,9 @@ typedef enum : NSUInteger { // Do nothing } -- (void)handleUnsentMessageTap:(TSOutgoingMessage *)message +- (void)handleUnsentMessageTap:(TSOutgoingMessage *)tsMessage { - UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:message.mostRecentFailureText + UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:tsMessage.mostRecentFailureText message:nil preferredStyle:UIAlertControllerStyleActionSheet]; @@ -1465,23 +1465,29 @@ typedef enum : NSUInteger { UIAlertAction *deleteMessageAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_DELETE_TITLE", @"") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { - [self remove:message]; + [self remove:tsMessage]; }]; [actionSheet addAction:deleteMessageAction]; - // TODO TODO TODO + UIAlertAction *resendMessageAction = [UIAlertAction + actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") + accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + SNVisibleMessage *message = [SNVisibleMessage from:tsMessage]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSMutableArray *attachments = @[].mutableCopy; + for (NSString *attachmentID in tsMessage.attachmentIds) { + TSAttachmentStream *stream = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID transaction:transaction]; + if (![stream isKindOfClass:TSAttachmentStream.class]) { continue; } + [attachments addObject:stream]; + } + [SNMessageSender prep:attachments forMessage:message usingTransaction: transaction]; + [SNMessageSender send:message inThread:self.thread usingTransaction:transaction]; + }]; + }]; -// UIAlertAction *resendMessageAction = [UIAlertAction -// actionWithTitle:NSLocalizedString(@"SEND_AGAIN_BUTTON", @"") -// accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"send_again") -// style:UIAlertActionStyleDefault -// handler:^(UIAlertAction *action) { -// [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { -// [self.messageSenderJobQueue addMessage:message transaction:transaction]; -// }]; -// }]; - -// [actionSheet addAction:resendMessageAction]; + [actionSheet addAction:resendMessageAction]; [self dismissKeyBoard]; [self presentAlert:actionSheet]; diff --git a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift index b0d343520..7b55c0c32 100644 --- a/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ClosedGroupUpdate.swift @@ -6,11 +6,20 @@ public final class ClosedGroupUpdate : ControlMessage { public var kind: Kind? // MARK: Kind - public enum Kind { + public enum Kind : CustomStringConvertible { case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) case info(groupPublicKey: Data, name: String, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data]) case senderKeyRequest(groupPublicKey: Data) case senderKey(groupPublicKey: Data, senderKey: ClosedGroupSenderKey) + + public var description: String { + switch self { + case .new: return "new" + case .info: return "info" + case .senderKeyRequest: return "senderKeyRequest" + case .senderKey: return "senderKey" + } + } } // MARK: Initialization @@ -154,6 +163,15 @@ public final class ClosedGroupUpdate : ControlMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + ClosedGroupUpdate( + kind: \(kind?.description ?? "null") + ) + """ + } } private extension ClosedGroupSenderKey { diff --git a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift index e922a54d9..7c2f221dc 100644 --- a/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift +++ b/SessionMessagingKit/Messages/Control Messages/ExpirationTimerUpdate.swift @@ -56,6 +56,15 @@ public final class ExpirationTimerUpdate : ControlMessage { } } + // MARK: Description + public override var description: String { + """ + ExpirationTimerUpdate( + duration: \(duration?.description ?? "null") + ) + """ + } + // MARK: Convenience @objc public func setDuration(_ duration: UInt32) { self.duration = duration diff --git a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift index 0c5d5ecf5..5199d8980 100644 --- a/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift +++ b/SessionMessagingKit/Messages/Control Messages/ReadReceipt.swift @@ -54,4 +54,13 @@ public final class ReadReceipt : ControlMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + ReadReceipt( + timestamps: \(timestamps?.description ?? "null") + ) + """ + } } diff --git a/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift index a867d77b2..6d094cd62 100644 --- a/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift +++ b/SessionMessagingKit/Messages/Control Messages/TypingIndicator.swift @@ -7,7 +7,7 @@ public final class TypingIndicator : ControlMessage { public override class var ttl: UInt64 { 30 * 1000 } // MARK: Kind - public enum Kind : Int { + public enum Kind : Int, CustomStringConvertible { case started, stopped static func fromProto(_ proto: SNProtoTypingMessage.SNProtoTypingMessageAction) -> Kind { @@ -23,6 +23,13 @@ public final class TypingIndicator : ControlMessage { case .stopped: return .stopped } } + + public var description: String { + switch self { + case .started: return "started" + case .stopped: return "stopped" + } + } } // MARK: Validation @@ -72,4 +79,13 @@ public final class TypingIndicator : ControlMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + TypingIndicator( + kind: \(kind?.description ?? "null") + ) + """ + } } diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift index 5cf891342..c23e5e7ef 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage+Conversion.swift @@ -1,3 +1,4 @@ +import SessionUtilitiesKit @objc public extension TSOutgoingMessage { @@ -21,3 +22,23 @@ ) } } + +@objc public extension VisibleMessage { + + @objc(from:) + static func from(_ tsMessage: TSOutgoingMessage) -> VisibleMessage { + let result = VisibleMessage() + result.threadID = tsMessage.uniqueThreadId + result.sentTimestamp = tsMessage.timestamp + result.recipient = tsMessage.recipientIds().first + if let thread = tsMessage.thread as? TSGroupThread, thread.usesSharedSenderKeys { + let groupID = thread.groupModel.groupId + result.groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) + } + result.text = tsMessage.body + result.attachmentIDs = tsMessage.attachmentIds.compactMap { $0 as? String } + result.quote = VisibleMessage.Quote.from(tsMessage.quotedMessage) + result.linkPreview = VisibleMessage.LinkPreview.from(tsMessage.linkPreview) + return result + } +} diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift index 587c5380f..f1f4053af 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+LinkPreview.swift @@ -56,5 +56,16 @@ public extension VisibleMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + LinkPreview( + title: \(title ?? "null") + url: \(url ?? "null") + attachmentID: \(attachmentID ?? "null") + ) + """ + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift index 9ea0ff7e1..71bec53c3 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Profile.swift @@ -57,5 +57,16 @@ public extension VisibleMessage { return nil } } + + // MARK: Description + public override var description: String { + """ + Profile( + displayName: \(displayName ?? "null") + profileKey: \(profileKey?.description ?? "null") + profilePictureURL: \(profilePictureURL ?? "null") + ) + """ + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift index b096b7192..d2ad216e9 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage+Quote.swift @@ -66,8 +66,9 @@ public extension VisibleMessage { guard let stream = TSAttachmentStream.fetch(uniqueId: attachmentID, transaction: transaction), stream.isUploaded else { #if DEBUG preconditionFailure("Sending a message before all associated attachments have been uploaded.") - #endif + #else return + #endif } let quotedAttachmentProto = SNProtoDataMessageQuoteQuotedAttachment.builder() quotedAttachmentProto.setContentType(stream.contentType) @@ -82,5 +83,17 @@ public extension VisibleMessage { SNLog("Couldn't construct quoted attachment proto from: \(self).") } } + + // MARK: Description + public override var description: String { + """ + Quote( + timestamp: \(timestamp?.description ?? "null") + publicKey: \(publicKey ?? "null") + text: \(text ?? "null") + attachmentID: \(attachmentID ?? "null") + ) + """ + } } } diff --git a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift index 6b05102df..a25735ce2 100644 --- a/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift +++ b/SessionMessagingKit/Messages/Visible Messages/VisibleMessage.swift @@ -99,4 +99,18 @@ public final class VisibleMessage : Message { return nil } } + + // MARK: Description + public override var description: String { + """ + VisibleMessage( + text: \(text ?? "null") + attachmentIDs: \(attachmentIDs) + quote: \(quote?.description ?? "null") + linkPreview: \(linkPreview?.description ?? "null") + contact: \(contact?.description ?? "null") + profile: \(profile?.description ?? "null") + ) + """ + } } diff --git a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift index 59f3f15f6..5bb5c3c7f 100644 --- a/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Link Previews/OWSLinkPreview+Conversion.swift @@ -9,6 +9,11 @@ extension OWSLinkPreview { extension VisibleMessage.LinkPreview { + public static func from(_ linkPreview: OWSLinkPreview?) -> VisibleMessage.LinkPreview? { + guard let linkPreview = linkPreview else { return nil } + return VisibleMessage.LinkPreview(title: linkPreview.title, url: linkPreview.urlString!, attachmentID: linkPreview.imageAttachmentId) + } + @objc(from:using:) public static func from(_ linkPreview: OWSLinkPreviewDraft?, using transaction: YapDatabaseReadWriteTransaction) -> VisibleMessage.LinkPreview? { guard let linkPreview = linkPreview else { return nil } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 063075333..2e43bb6c8 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -59,6 +59,19 @@ public final class MessageSender : NSObject { attachment.write($0.dataSource) attachment.save(with: transaction) } + prep(attachments, for: message, using: transaction) + } + + @objc(prep:forMessage:usingTransaction:) + public static func prep(_ attachmentStreams: [TSAttachmentStream], for message: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) { + guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { + #if DEBUG + preconditionFailure() + #else + return + #endif + } + var attachments = attachmentStreams // The line below locally generates a thumbnail for the quoted attachment. It just needs to happen at some point during the // message sending process. tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) @@ -71,6 +84,7 @@ public final class MessageSender : NSObject { // Anything added to message.attachmentIDs will be uploaded by an UploadAttachmentJob. Any attachment IDs added to tsMessage will // make it render as an attachment (not what we want in the case of a link preview or quoted attachment). message.attachmentIDs = attachments.map { $0.uniqueId! } + tsMessage.attachmentIds.removeAllObjects() tsMessage.attachmentIds.addObjects(from: message.attachmentIDs) if let id = linkPreviewAttachmentID { tsMessage.attachmentIds.remove(id) } tsMessage.save(with: transaction) @@ -109,7 +123,9 @@ public final class MessageSender : NSObject { func handleFailure(with error: Swift.Error, using transaction: YapDatabaseReadWriteTransaction) { MessageSender.handleFailedMessageSend(message, with: error, using: transaction) if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { - NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) + DispatchQueue.main.async { + NotificationCenter.default.post(name: .messageSendingFailed, object: NSNumber(value: message.sentTimestamp!)) + } } seal.reject(error) } @@ -217,7 +233,9 @@ public final class MessageSender : NSObject { guard !isSuccess else { return } // Succeed as soon as the first promise succeeds isSuccess = true if case .contact(_) = destination, message is VisibleMessage, !isSelfSend { - NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) + DispatchQueue.main.async { + NotificationCenter.default.post(name: .messageSent, object: NSNumber(value: message.sentTimestamp!)) + } } storage.withAsync({ transaction in MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction) diff --git a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift index 377317376..9cdf974d1 100644 --- a/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift +++ b/SessionMessagingKit/Sending & Receiving/Quotes/TSQuotedMessage+Conversion.swift @@ -16,3 +16,16 @@ extension TSQuotedMessage { ) } } + +extension VisibleMessage.Quote { + + public static func from(_ quote: TSQuotedMessage?) -> VisibleMessage.Quote? { + guard let quote = quote else { return nil } + let result = VisibleMessage.Quote() + result.timestamp = quote.timestamp + result.publicKey = quote.authorId + result.text = quote.body + result.attachmentID = quote.quotedAttachments.first?.attachmentId + return result + } +} diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift index fb79c5f34..bb7279306 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift @@ -22,6 +22,11 @@ extension MessageSender { return AnyPromise.from(sendNonDurably(message, with: attachments, in: thread, using: transaction)) } + @objc(sendNonDurably:withAttachmentIDs:inThread:usingTransaction:) + public static func objc_sendNonDurably(_ message: VisibleMessage, with attachmentIDs: [String], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { + return AnyPromise.from(sendNonDurably(message, with: attachmentIDs, in: thread, using: transaction)) + } + @objc(sendNonDurably:inThread:usingTransaction:) public static func objc_sendNonDurably(_ message: Message, in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> AnyPromise { return AnyPromise.from(sendNonDurably(message, in: thread, using: transaction)) @@ -29,7 +34,11 @@ extension MessageSender { public static func sendNonDurably(_ message: VisibleMessage, with attachments: [SignalAttachment], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { prep(attachments, for: message, using: transaction) - let attachments = message.attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } + return sendNonDurably(message, with: message.attachmentIDs, in: thread, using: transaction) + } + + public static func sendNonDurably(_ message: VisibleMessage, with attachmentIDs: [String], in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> Promise { + let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) } let attachmentsToUpload = attachments.filter { !$0.isUploaded } let attachmentUploadPromises: [Promise] = attachmentsToUpload.map { stream in let openGroup = SNMessagingKitConfiguration.shared.storage.getOpenGroup(for: thread.uniqueId!) diff --git a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m index a30c44d9c..ea8332eb6 100644 --- a/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m +++ b/SignalUtilitiesKit/UI/SharingThreadPickerViewController.m @@ -414,10 +414,10 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); }); } -- (void)resendMessage:(TSOutgoingMessage *)message fromViewController:(UIViewController *)fromViewController +- (void)resendMessage:(TSOutgoingMessage *)tsMessage fromViewController:(UIViewController *)fromViewController { OWSAssertIsOnMainThread(); - OWSAssertDebug(message); + OWSAssertDebug(tsMessage); OWSAssertDebug(fromViewController); NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title"); @@ -434,29 +434,26 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); [fromViewController presentAlert:progressAlert - completion:^{ - - // TODO TODO TODO - -// [self.messageSender sendMessage:message -// success:^{ -// OWSLogInfo(@"Resending attachment succeeded."); -// dispatch_async(dispatch_get_main_queue(), ^{ -// [self.shareViewDelegate shareViewWasCompleted]; -// }); -// } -// failure:^(NSError *error) { -// dispatch_async(dispatch_get_main_queue(), ^{ -// [fromViewController -// dismissViewControllerAnimated:YES -// completion:^{ -// OWSLogInfo(@"Sending attachment failed with error: %@", error); -// [self showSendFailureAlertWithError:error -// message:message -// fromViewController:fromViewController]; -// }]; -// }); -// }]; + completion:^{ + SNVisibleMessage *message = [SNVisibleMessage from:tsMessage]; + [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSMutableArray *attachments = @[].mutableCopy; + for (NSString *attachmentID in tsMessage.attachmentIds) { + TSAttachmentStream *stream = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID transaction:transaction]; + if (![stream isKindOfClass:TSAttachmentStream.class]) { continue; } + [attachments addObject:stream]; + } + [SNMessageSender prep:attachments forMessage:message usingTransaction: transaction]; + [SNMessageSender sendNonDurably:message withAttachmentIDs:tsMessage.attachmentIds inThread:self.thread usingTransaction:transaction] + .thenOn(dispatch_get_main_queue(), ^() { + [self.shareViewDelegate shareViewWasCompleted]; + }) + .catchOn(dispatch_get_main_queue(), ^(NSError *error) { + [fromViewController dismissViewControllerAnimated:YES completion:^{ + [self showSendFailureAlertWithError:error message:tsMessage fromViewController:fromViewController]; + }]; + }); + }]; }]; }