From eaab6ee22d6f030668ef258ee5b0a4a92244231c Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 5 Aug 2021 13:34:07 +1000 Subject: [PATCH] deleted message UI in conversation screen --- Session.xcodeproj/project.pbxproj | 4 ++ Session/Conversations/ConversationViewItem.h | 1 + Session/Conversations/ConversationViewItem.m | 5 ++ .../Content Views/DeletedMessageView.swift | 51 +++++++++++++++++++ .../Message Cells/VisibleMessageCell.swift | 4 ++ .../Messages/Signal/TSMessage.h | 3 ++ .../Messages/Signal/TSMessage.m | 18 +++++++ .../MessageReceiver+Handling.swift | 2 +- 8 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index ce1dbb470..d5f734869 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -137,6 +137,7 @@ 76C87F19181EFCE600C4ACAB /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */; }; 76EB054018170B33006006FC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB03C318170B33006006FC /* AppDelegate.m */; }; 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */; }; + 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; }; 7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */; }; 7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; }; @@ -1099,6 +1100,7 @@ 76EB03C218170B33006006FC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 76EB03C318170B33006006FC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = ""; }; + 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessageView.swift; sourceTree = ""; }; 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = ""; }; 7BC01A3F241F40AB00BC7C55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -2089,6 +2091,7 @@ B849789525D4A2F500D0D0B3 /* LinkPreviewView.swift */, B8D84EA225DF745A005A043E /* LinkPreviewState.swift */, B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */, + 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */, ); path = "Content Views"; sourceTree = ""; @@ -4903,6 +4906,7 @@ B8D0A25025E3678700C1835E /* LinkDeviceVC.swift in Sources */, 3496957321A301A100DCFE74 /* OWSBackupJob.m in Sources */, B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */, + 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */, B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */, 346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */, 45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */, diff --git a/Session/Conversations/ConversationViewItem.h b/Session/Conversations/ConversationViewItem.h index e514ba3f8..307aaf2a1 100644 --- a/Session/Conversations/ConversationViewItem.h +++ b/Session/Conversations/ConversationViewItem.h @@ -15,6 +15,7 @@ typedef NS_ENUM(NSInteger, OWSMessageCellType) { OWSMessageCellType_GenericAttachment, OWSMessageCellType_MediaMessage, OWSMessageCellType_OversizeTextDownloading, + OWSMessageCellType_DeletedMessage }; NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType); diff --git a/Session/Conversations/ConversationViewItem.m b/Session/Conversations/ConversationViewItem.m index e9db68a4e..7fe2c6e61 100644 --- a/Session/Conversations/ConversationViewItem.m +++ b/Session/Conversations/ConversationViewItem.m @@ -470,6 +470,11 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType) self.hasViewState = YES; TSMessage *message = (TSMessage *)self.interaction; + + if (message.isDeleted) { + self.messageCellType = OWSMessageCellType_DeletedMessage; + return; + } // Check for quoted replies _before_ media album handling, // since that logic may exit early. diff --git a/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift b/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift new file mode 100644 index 000000000..3e2d777f1 --- /dev/null +++ b/Session/Conversations/Message Cells/Content Views/DeletedMessageView.swift @@ -0,0 +1,51 @@ + +final class DeletedMessageView : UIView { + private let viewItem: ConversationViewItem + private let textColor: UIColor + + // MARK: Settings + private static let iconSize: CGFloat = 18 + private static let iconImageViewSize: CGFloat = 30 + + // MARK: Lifecycle + init(viewItem: ConversationViewItem, textColor: UIColor) { + self.viewItem = viewItem + self.textColor = textColor + super.init(frame: CGRect.zero) + setUpViewHierarchy() + } + + override init(frame: CGRect) { + preconditionFailure("Use init(viewItem:textColor:) instead.") + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(viewItem:textColor:) instead.") + } + + private func setUpViewHierarchy() { + // Image view + let iconSize = DeletedMessageView.iconSize + let icon = UIImage(named: "ic_trash")?.withTint(textColor)?.resizedImage(to: CGSize(width: iconSize, height: iconSize)) + let imageView = UIImageView(image: icon) + imageView.contentMode = .center + let iconImageViewSize = DeletedMessageView.iconImageViewSize + imageView.set(.width, to: iconImageViewSize) + imageView.set(.height, to: iconImageViewSize) + // Body label + let titleLabel = UILabel() + titleLabel.lineBreakMode = .byTruncatingTail + titleLabel.text = "This message has been deleted." + titleLabel.textColor = textColor + titleLabel.font = .systemFont(ofSize: Values.smallFontSize) + // Stack view + let stackView = UIStackView(arrangedSubviews: [ imageView, titleLabel ]) + stackView.axis = .horizontal + stackView.alignment = .center + stackView.isLayoutMarginsRelativeArrangement = true + stackView.layoutMargins = UIEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 6) + addSubview(stackView) + stackView.pin(to: self, withInset: Values.smallSpacing) + } +} + diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 7b0725944..dd1849e0a 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -389,6 +389,10 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { snContentView.addSubview(documentView) documentView.pin(to: snContentView) } + case .deletedMessage: + let deletedMessageView = DeletedMessageView(viewItem: viewItem, textColor: bodyLabelTextColor) + snContentView.addSubview(deletedMessageView) + deletedMessageView.pin(to: snContentView) default: return } } diff --git a/SessionMessagingKit/Messages/Signal/TSMessage.h b/SessionMessagingKit/Messages/Signal/TSMessage.h index e467e30a5..ff581bb16 100644 --- a/SessionMessagingKit/Messages/Signal/TSMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSMessage.h @@ -39,6 +39,7 @@ extern const NSUInteger kOversizeTextMessageSizeThreshold; @property (nonatomic, readonly, nullable) NSString *openGroupInvitationName; @property (nonatomic, readonly, nullable) NSString *openGroupInvitationURL; @property (nonatomic, nullable) NSString *serverHash; +@property (nonatomic) BOOL isDeleted; - (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE; @@ -82,6 +83,8 @@ extern const NSUInteger kOversizeTextMessageSizeThreshold; - (void)updateWithLinkPreview:(OWSLinkPreview *)linkPreview transaction:(YapDatabaseReadWriteTransaction *)transaction; +- (void)updateForDeletionWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Messages/Signal/TSMessage.m b/SessionMessagingKit/Messages/Signal/TSMessage.m index 3da975777..59548cae7 100644 --- a/SessionMessagingKit/Messages/Signal/TSMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSMessage.m @@ -86,6 +86,7 @@ const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; _openGroupInvitationName = openGroupInvitationName; _openGroupInvitationURL = openGroupInvitationURL; _serverHash = serverHash; + _isDeleted = false; return self; } @@ -423,6 +424,23 @@ const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024; }]; } +- (void)updateForDeletionWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [self applyChangeToSelfAndLatestCopy:transaction + changeBlock:^(TSMessage *message) { + [message setBody:nil]; + [message setServerHash:nil]; + for (NSString *attachmentId in message.attachmentIds) { + TSAttachment *_Nullable attachment = + [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; + if (attachment) { + [attachment removeWithTransaction:transaction]; + } + } + [message setIsDeleted:true]; + }]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 8a3630aa8..637bb051f 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -234,7 +234,7 @@ extension MessageReceiver { if let serverHash = messageToDelete.serverHash { SnodeAPI.deleteMessage(publicKey: author, serverHashes: [serverHash]).retainUntilComplete() } - messageToDelete.remove(with: transaction) + messageToDelete.updateForDeletion(with: transaction) } }