From 8c897dcc3d332f426ae6dd4360974b55cc67bbfa Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 5 Aug 2021 15:59:23 +1000 Subject: [PATCH] use action sheet to show options for deleting a message --- .../Context Menu/ContextMenuVC+Action.swift | 57 +++---------------- .../ContextMenuVC+ActionView.swift | 20 +++---- .../Context Menu/ContextMenuVC.swift | 34 +++++------ .../ConversationVC+Interaction.swift | 17 +++++- 4 files changed, 46 insertions(+), 82 deletions(-) diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index e77b1379b..e05e0cae9 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -2,82 +2,45 @@ extension ContextMenuVC { struct Action { - let icon: UIImage? + let icon: UIImage let title: String - let tag: String let work: () -> Void static func reply(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Reply" - let tag = "reply" - return Action(icon: UIImage(named: "ic_reply")!, title: title, tag: tag) { delegate?.reply(viewItem) } + return Action(icon: UIImage(named: "ic_reply")!, title: title) { delegate?.reply(viewItem) } } static func copy(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Copy" - let tag = "copy" - return Action(icon: UIImage(named: "ic_copy")!, title: title, tag: tag) { delegate?.copy(viewItem) } + return Action(icon: UIImage(named: "ic_copy")!, title: title) { delegate?.copy(viewItem) } } static func copySessionID(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Copy Session ID" - let tag = "copySessionID" - return Action(icon: UIImage(named: "ic_copy")!, title: title, tag: tag) { delegate?.copySessionID(viewItem) } + return Action(icon: UIImage(named: "ic_copy")!, title: title) { delegate?.copySessionID(viewItem) } } static func delete(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Delete" - let tag = "delete" - return Action(icon: UIImage(named: "ic_trash")!, title: title, tag: tag) { delegate?.delete(viewItem) } - } - - static func deleteLocally(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { - let title = "Delete for me" - let tag = "deleteforme" - return Action(icon: nil, title: title, tag: tag) { delegate?.deleteLocally(viewItem) } - } - - static func deleteForEveryone(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { - let tag = "deleteforeveryone" - var title = "Delete for everyone" - if !viewItem.isGroupThread { - title = "Delete for me and \(viewItem.interaction.thread.name())" - } - return Action(icon: nil, title: title, tag: tag) { delegate?.deleteForEveryone(viewItem) } + return Action(icon: UIImage(named: "ic_trash")!, title: title) { delegate?.delete(viewItem) } } static func save(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Save" - let tag = "save" - return Action(icon: UIImage(named: "ic_download")!, title: title, tag: tag) { delegate?.save(viewItem) } + return Action(icon: UIImage(named: "ic_download")!, title: title) { delegate?.save(viewItem) } } static func ban(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Ban User" - let tag = "banUser" - return Action(icon: UIImage(named: "ic_block")!, title: title, tag: tag) { delegate?.ban(viewItem) } + return Action(icon: UIImage(named: "ic_block")!, title: title) { delegate?.ban(viewItem) } } static func banAndDeleteAllMessages(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Ban and Delete All" - let tag = "banAndDeleteAll" - return Action(icon: UIImage(named: "ic_block")!, title: title, tag: tag) { delegate?.banAndDeleteAllMessages(viewItem) } + return Action(icon: UIImage(named: "ic_block")!, title: title) { delegate?.banAndDeleteAllMessages(viewItem) } } } - - static func deleteActions(for viewItem: ConversationViewItem, delegate: ContextMenuActionDelegate?) -> [Action] { - switch viewItem.interaction.interactionType() { - case .outgoingMessage: - if let message = viewItem.interaction as? TSMessage, let _ = message.serverHash { - return [Action.deleteForEveryone(viewItem, delegate), Action.deleteLocally(viewItem, delegate)] - } - return [Action.deleteLocally(viewItem, delegate)] - case .incomingMessage: - return [Action.deleteLocally(viewItem, delegate)] - default: return [] // Should never occur - } - - } static func actions(for viewItem: ConversationViewItem, delegate: ContextMenuActionDelegate?) -> [Action] { func isReplyingAllowed() -> Bool { @@ -119,14 +82,12 @@ extension ContextMenuVC { } // MARK: Delegate -protocol ContextMenuActionDelegate : class { +protocol ContextMenuActionDelegate : AnyObject { func reply(_ viewItem: ConversationViewItem) func copy(_ viewItem: ConversationViewItem) func copySessionID(_ viewItem: ConversationViewItem) func delete(_ viewItem: ConversationViewItem) - func deleteLocally(_ viewItem: ConversationViewItem) - func deleteForEveryone(_ viewItem: ConversationViewItem) func save(_ viewItem: ConversationViewItem) func ban(_ viewItem: ConversationViewItem) func banAndDeleteAllMessages(_ viewItem: ConversationViewItem) diff --git a/Session/Conversations/Context Menu/ContextMenuVC+ActionView.swift b/Session/Conversations/Context Menu/ContextMenuVC+ActionView.swift index 1ff6b8ab6..0f0e99ffc 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+ActionView.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+ActionView.swift @@ -26,25 +26,20 @@ extension ContextMenuVC { } private func setUpViewHierarchy() { - var subviews: [UIView] = [] // Icon - if let icon = action.icon { - let iconSize = ActionView.iconSize - let iconImageView = UIImageView(image: icon.resizedImage(to: CGSize(width: iconSize, height: iconSize))!.withTint(Colors.text)) - let iconImageViewSize = ActionView.iconImageViewSize - iconImageView.set(.width, to: iconImageViewSize) - iconImageView.set(.height, to: iconImageViewSize) - iconImageView.contentMode = .center - subviews.append(iconImageView) - } + let iconSize = ActionView.iconSize + let iconImageView = UIImageView(image: action.icon.resizedImage(to: CGSize(width: iconSize, height: iconSize))!.withTint(Colors.text)) + let iconImageViewSize = ActionView.iconImageViewSize + iconImageView.set(.width, to: iconImageViewSize) + iconImageView.set(.height, to: iconImageViewSize) + iconImageView.contentMode = .center // Title let titleLabel = UILabel() titleLabel.text = action.title titleLabel.textColor = Colors.text titleLabel.font = .systemFont(ofSize: Values.mediumFontSize) - subviews.append(titleLabel) // Stack view - let stackView = UIStackView(arrangedSubviews: subviews) + let stackView = UIStackView(arrangedSubviews: [ iconImageView, titleLabel ]) stackView.axis = .horizontal stackView.spacing = Values.smallSpacing stackView.alignment = .center @@ -61,7 +56,6 @@ extension ContextMenuVC { // MARK: Interaction @objc private func handleTap() { action.work() - guard action.tag != "delete" else { return } dismiss() } } diff --git a/Session/Conversations/Context Menu/ContextMenuVC.swift b/Session/Conversations/Context Menu/ContextMenuVC.swift index 14cfc785a..66cf13925 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC.swift @@ -75,7 +75,20 @@ final class ContextMenuVC : UIViewController { } else { timestampLabel.pin(.left, to: .right, of: snapshot, withInset: Values.smallSpacing) } - let menuHeight = self.updateMenu() + // Menu + let menuBackgroundView = UIView() + menuBackgroundView.backgroundColor = Colors.receivedMessageBackground + menuBackgroundView.layer.cornerRadius = ContextMenuVC.menuCornerRadius + menuBackgroundView.layer.masksToBounds = true + menuView.addSubview(menuBackgroundView) + menuBackgroundView.pin(to: menuView) + let actionViews = ContextMenuVC.actions(for: viewItem, delegate: delegate).map { ActionView(for: $0, dismiss: snDismiss) } + let menuStackView = UIStackView(arrangedSubviews: actionViews) + menuStackView.axis = .vertical + menuView.addSubview(menuStackView) + menuStackView.pin(to: menuView) + view.addSubview(menuView) + let menuHeight = CGFloat(actionViews.count) * ContextMenuVC.actionViewHeight let spacing = Values.smallSpacing let margin = max(UIApplication.shared.keyWindow!.safeAreaInsets.bottom, Values.mediumSpacing) if frame.maxY + spacing + menuHeight > UIScreen.main.bounds.height - margin { @@ -106,25 +119,6 @@ final class ContextMenuVC : UIViewController { super.viewDidLayoutSubviews() menuView.layer.shadowPath = UIBezierPath(roundedRect: menuView.bounds, cornerRadius: ContextMenuVC.menuCornerRadius).cgPath } - - func updateMenu(forDelete: Bool = false) -> CGFloat { - // Menu: return the menuHeight - menuView.subviews.forEach({ $0.removeFromSuperview() }) - let menuBackgroundView = UIView() - menuBackgroundView.backgroundColor = Colors.receivedMessageBackground - menuBackgroundView.layer.cornerRadius = ContextMenuVC.menuCornerRadius - menuBackgroundView.layer.masksToBounds = true - menuView.addSubview(menuBackgroundView) - menuBackgroundView.pin(to: menuView) - let actions = forDelete ? ContextMenuVC.deleteActions(for: viewItem, delegate: delegate) : ContextMenuVC.actions(for: viewItem, delegate: delegate) - let actionViews = actions.map { ActionView(for: $0, dismiss: snDismiss) } - let menuStackView = UIStackView(arrangedSubviews: actionViews) - menuStackView.axis = .vertical - menuView.addSubview(menuStackView) - menuStackView.pin(to: menuView) - view.addSubview(menuView) - return CGFloat(actionViews.count) * ContextMenuVC.actionViewHeight - } // MARK: Interaction @objc private func handleTap() { diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 527a6ff3e..1d78193a6 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -546,7 +546,22 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc } func delete(_ viewItem: ConversationViewItem) { - let _ = self.contextMenuVC?.updateMenu(forDelete: true) + let alertVC = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet) + let deleteLocallyAction = UIAlertAction.init(title: "Delete just for me", style: .destructive) { _ in + self.deleteLocally(viewItem) + } + var title = "Delete for everyone" + if !viewItem.isGroupThread { + title = "Delete for me and \(viewItem.interaction.thread.name())" + } + let deleteRemotelyAction = UIAlertAction.init(title: title, style: .destructive) { _ in + self.deleteForEveryone(viewItem) + } + let cancelAction = UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil) + alertVC.addAction(deleteLocallyAction) + alertVC.addAction(deleteRemotelyAction) + alertVC.addAction(cancelAction) + self.navigationController?.presentAlert(alertVC) } private func buildUsendRequest(_ viewItem: ConversationViewItem) -> UnsendRequest? {