From 81b29394ecf1e9cfe83f8b4f6df5b54d95034d74 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 15 Feb 2021 15:42:16 +1100 Subject: [PATCH] Implement resending of failed messages --- .../ConversationVC+Interaction.swift | 64 ++++++++++--------- Session/Conversations V2/ConversationVC.swift | 28 +++++++- .../Message Cells/VisibleMessageCell.swift | 2 +- .../Views & Modals/LinkPreviewModal.swift | 2 +- 4 files changed, 63 insertions(+), 33 deletions(-) diff --git a/Session/Conversations V2/ConversationVC+Interaction.swift b/Session/Conversations V2/ConversationVC+Interaction.swift index 73a70612b..6e547866e 100644 --- a/Session/Conversations V2/ConversationVC+Interaction.swift +++ b/Session/Conversations V2/ConversationVC+Interaction.swift @@ -85,40 +85,44 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc } func handleViewItemTapped(_ viewItem: ConversationViewItem, gestureRecognizer: UITapGestureRecognizer) { - switch viewItem.messageCellType { - case .audio: playOrPauseAudio(for: viewItem) - case .mediaMessage: - guard let index = viewItems.firstIndex(where: { $0 === viewItem }), - let cell = messagesTableView.cellForRow(at: IndexPath(row: index, section: 0)) as? VisibleMessageCell, let albumView = cell.albumView else { return } - let locationInCell = gestureRecognizer.location(in: cell) - if let overlayView = cell.mediaTextOverlayView { - let locationInOverlayView = cell.convert(locationInCell, to: overlayView) - if let readMoreButton = overlayView.readMoreButton, readMoreButton.frame.contains(locationInOverlayView) { - return showFullText(viewItem) // FIXME: Bit of a hack to do it this way + if let message = viewItem.interaction as? TSOutgoingMessage, message.messageState == .failed { + showFailedMessageSheet(for: message) + } else { + switch viewItem.messageCellType { + case .audio: playOrPauseAudio(for: viewItem) + case .mediaMessage: + guard let index = viewItems.firstIndex(where: { $0 === viewItem }), + let cell = messagesTableView.cellForRow(at: IndexPath(row: index, section: 0)) as? VisibleMessageCell, let albumView = cell.albumView else { return } + let locationInCell = gestureRecognizer.location(in: cell) + if let overlayView = cell.mediaTextOverlayView { + let locationInOverlayView = cell.convert(locationInCell, to: overlayView) + if let readMoreButton = overlayView.readMoreButton, readMoreButton.frame.contains(locationInOverlayView) { + return showFullText(viewItem) // FIXME: Bit of a hack to do it this way + } } - } - let locationInAlbumView = cell.convert(locationInCell, to: albumView) - guard let mediaView = albumView.mediaView(forLocation: locationInAlbumView) else { return } - if albumView.isMoreItemsView(mediaView: mediaView) && viewItem.mediaAlbumHasFailedAttachment() { - // TODO: Tapped a failed incoming attachment - } - let attachment = mediaView.attachment - if let pointer = attachment as? TSAttachmentPointer { - if pointer.state == .failed { + let locationInAlbumView = cell.convert(locationInCell, to: albumView) + guard let mediaView = albumView.mediaView(forLocation: locationInAlbumView) else { return } + if albumView.isMoreItemsView(mediaView: mediaView) && viewItem.mediaAlbumHasFailedAttachment() { // TODO: Tapped a failed incoming attachment } + let attachment = mediaView.attachment + if let pointer = attachment as? TSAttachmentPointer { + if pointer.state == .failed { + // TODO: Tapped a failed incoming attachment + } + } + guard let stream = attachment as? TSAttachmentStream else { return } + let gallery = MediaGallery(thread: thread, options: [ .sliderEnabled, .showAllMediaButton ]) + gallery.presentDetailView(fromViewController: self, mediaAttachment: stream, replacingView: mediaView) + case .genericAttachment: + guard let url = viewItem.attachmentStream?.originalMediaURL else { return } + let shareVC = UIActivityViewController(activityItems: [ url ], applicationActivities: nil) + navigationController!.present(shareVC, animated: true, completion: nil) + case .textOnlyMessage: + guard let preview = viewItem.linkPreview, let urlAsString = preview.urlString, let url = URL(string: urlAsString) else { return } + openURL(url) + default: break } - guard let stream = attachment as? TSAttachmentStream else { return } - let gallery = MediaGallery(thread: thread, options: [ .sliderEnabled, .showAllMediaButton ]) - gallery.presentDetailView(fromViewController: self, mediaAttachment: stream, replacingView: mediaView) - case .genericAttachment: - guard let url = viewItem.attachmentStream?.originalMediaURL else { return } - let shareVC = UIActivityViewController(activityItems: [ url ], applicationActivities: nil) - navigationController!.present(shareVC, animated: true, completion: nil) - case .textOnlyMessage: - guard let preview = viewItem.linkPreview, let urlAsString = preview.urlString, let url = URL(string: urlAsString) else { return } - openURL(url) - default: break } } diff --git a/Session/Conversations V2/ConversationVC.swift b/Session/Conversations V2/ConversationVC.swift index aa94a4979..464ab94bf 100644 --- a/Session/Conversations V2/ConversationVC.swift +++ b/Session/Conversations V2/ConversationVC.swift @@ -4,7 +4,6 @@ // • Mentions // • Remaining send logic // • Subtitle -// • Resending failed messages // • Slight paging glitch // • Scrolling bug // • Scroll button bug @@ -361,6 +360,33 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, UITableViewD linkPreviewModel.modalTransitionStyle = .crossDissolve present(linkPreviewModel, animated: true, completion: nil) } + + func showFailedMessageSheet(for tsMessage: TSOutgoingMessage) { + let thread = self.thread + let sheet = UIAlertController(title: tsMessage.mostRecentFailureText, message: nil, preferredStyle: .actionSheet) + sheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) + sheet.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: { _ in + Storage.write { transaction in + tsMessage.remove(with: transaction) + Storage.shared.cancelPendingMessageSendJobIfNeeded(for: tsMessage.timestamp, using: transaction) + } + })) + sheet.addAction(UIAlertAction(title: "Resend", style: .default, handler: { _ in + let message = VisibleMessage.from(tsMessage) + Storage.write { transaction in + var attachments: [TSAttachmentStream] = [] + tsMessage.attachmentIds.forEach { attachmentID in + guard let attachmentID = attachmentID as? String else { return } + let attachment = TSAttachment.fetch(uniqueId: attachmentID, transaction: transaction) + guard let stream = attachment as? TSAttachmentStream else { return } + attachments.append(stream) + } + MessageSender.prep(attachments, for: message, using: transaction) + MessageSender.send(message, in: thread, using: transaction) + } + })) + present(sheet, animated: true, completion: nil) + } // MARK: Convenience private func getTitle() -> String { diff --git a/Session/Conversations V2/Message Cells/VisibleMessageCell.swift b/Session/Conversations V2/Message Cells/VisibleMessageCell.swift index ea2a6dd65..33495d2d3 100644 --- a/Session/Conversations V2/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations V2/Message Cells/VisibleMessageCell.swift @@ -480,7 +480,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewV2Delegate { case .read: backgroundColor = isLightMode ? .black : .white image = isLightMode ? #imageLiteral(resourceName: "FilledCircleCheckLightMode") : #imageLiteral(resourceName: "FilledCircleCheckDarkMode") - case .failed: image = #imageLiteral(resourceName: "message_status_failed").asTintedImage(color: Colors.text)! + case .failed: image = #imageLiteral(resourceName: "message_status_failed").asTintedImage(color: Colors.destructive)! } return (image, backgroundColor) } diff --git a/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift b/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift index eec119760..7b94e06ba 100644 --- a/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift +++ b/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift @@ -27,7 +27,7 @@ final class LinkPreviewModal : Modal { let messageLabel = UILabel() messageLabel.textColor = Colors.text messageLabel.font = .systemFont(ofSize: Values.smallFontSize) - let message = "Session can show previews for URLs. This will make your messaging experience nicer, but to generate a preview Session needs to contact the website in question. You can always disable link previews in the in-app settings." + let message = "Enabling link previews will show previews for URLs you send and receive. This can be useful, but Session will need to contact linked websites to generate previews. You can always disable link previews in Session's settings." messageLabel.text = message messageLabel.numberOfLines = 0 messageLabel.lineBreakMode = .byWordWrapping