From dfdffc607ca33060353bc35ae22698c2f0c3e3d3 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 14 Jul 2021 15:56:56 +1000 Subject: [PATCH] Make profile pictures tappable --- Session.xcodeproj/project.pbxproj | 4 ++ .../ConversationVC+Interaction.swift | 7 ++ .../Message Cells/MessageCell.swift | 3 +- .../Message Cells/VisibleMessageCell.swift | 5 +- .../Views & Modals/UserDetailsSheet.swift | 69 +++++++++++++++++++ 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 Session/Conversations/Views & Modals/UserDetailsSheet.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 1098ba918..6615e1d99 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -180,6 +180,7 @@ B83524A525C3BA4B0089A44F /* InfoMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83524A425C3BA4B0089A44F /* InfoMessageCell.swift */; }; B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; }; B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; + B848A4C5269EAAA200617031 /* UserDetailsSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B848A4C4269EAAA200617031 /* UserDetailsSheet.swift */; }; B849789625D4A2F500D0D0B3 /* LinkPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B849789525D4A2F500D0D0B3 /* LinkPreviewView.swift */; }; B84A89BC25DE328A0040017D /* ProfilePictureVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84A89BB25DE328A0040017D /* ProfilePictureVC.swift */; }; B85357BF23A1AE0800AAF6CD /* SeedReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */; }; @@ -1167,6 +1168,7 @@ B840729F2565F1670037CB17 /* OWSQuotedReplyModel+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OWSQuotedReplyModel+Conversion.swift"; sourceTree = ""; }; B84664F4235022F30083A1CD /* MentionUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionUtilities.swift; sourceTree = ""; }; B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B848A4C4269EAAA200617031 /* UserDetailsSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailsSheet.swift; sourceTree = ""; }; B849789525D4A2F500D0D0B3 /* LinkPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewView.swift; sourceTree = ""; }; B84A89BB25DE328A0040017D /* ProfilePictureVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePictureVC.swift; sourceTree = ""; }; B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedReminderView.swift; sourceTree = ""; }; @@ -2122,6 +2124,7 @@ B82149C025D605C6009C0F2A /* InfoBanner.swift */, B8214A2A25D63EB9009C0F2A /* MessagesTableView.swift */, C374EEEA25DA3CA70073A857 /* ConversationTitleView.swift */, + B848A4C4269EAAA200617031 /* UserDetailsSheet.swift */, ); path = "Views & Modals"; sourceTree = ""; @@ -4848,6 +4851,7 @@ C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */, B8569AD325CBA13D00DBA3DB /* MediaTextOverlayView.swift in Sources */, 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */, + B848A4C5269EAAA200617031 /* UserDetailsSheet.swift in Sources */, 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */, B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */, B8544E3323D50E4900299F14 /* SNAppearance.swift in Sources */, diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 632463bcb..2e8279e16 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -581,6 +581,13 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc func handleReplyButtonTapped(for viewItem: ConversationViewItem) { reply(viewItem) } + + func showUserDetails(for sessionID: String) { + let userDetailsSheet = UserDetailsSheet(for: sessionID) + userDetailsSheet.modalPresentationStyle = .overFullScreen + userDetailsSheet.modalTransitionStyle = .crossDissolve + present(userDetailsSheet, animated: true, completion: nil) + } // MARK: Voice Message Playback @objc func handleAudioDidFinishPlayingNotification(_ notification: Notification) { diff --git a/Session/Conversations/Message Cells/MessageCell.swift b/Session/Conversations/Message Cells/MessageCell.swift index 69f4dce25..d013ee3d7 100644 --- a/Session/Conversations/Message Cells/MessageCell.swift +++ b/Session/Conversations/Message Cells/MessageCell.swift @@ -48,7 +48,7 @@ class MessageCell : UITableViewCell { } } -protocol MessageCellDelegate : class { +protocol MessageCellDelegate : AnyObject { var lastSearchedText: String? { get } func getMediaCache() -> NSCache @@ -58,4 +58,5 @@ protocol MessageCellDelegate : class { func showFullText(_ viewItem: ConversationViewItem) func openURL(_ url: URL) func handleReplyButtonTapped(for viewItem: ConversationViewItem) + func showUserDetails(for sessionID: String) } diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index aa457bf00..7b0725944 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -449,7 +449,10 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { @objc private func handleTap(_ gestureRecognizer: UITapGestureRecognizer) { guard let viewItem = viewItem else { return } let location = gestureRecognizer.location(in: self) - if replyButton.frame.contains(location) { + if profilePictureView.frame.contains(location) && VisibleMessageCell.shouldShowProfilePicture(for: viewItem) { + guard let message = viewItem.interaction as? TSIncomingMessage else { return } + delegate?.showUserDetails(for: message.authorId) + } else if replyButton.frame.contains(location) { UIImpactFeedbackGenerator(style: .heavy).impactOccurred() reply() } else { diff --git a/Session/Conversations/Views & Modals/UserDetailsSheet.swift b/Session/Conversations/Views & Modals/UserDetailsSheet.swift new file mode 100644 index 000000000..5afc5518b --- /dev/null +++ b/Session/Conversations/Views & Modals/UserDetailsSheet.swift @@ -0,0 +1,69 @@ + +final class UserDetailsSheet : Sheet { + private let sessionID: String + + init(for sessionID: String) { + self.sessionID = sessionID + super.init(nibName: nil, bundle: nil) + } + + override init(nibName: String?, bundle: Bundle?) { + preconditionFailure("Use init(for:) instead.") + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(for:) instead.") + } + + override func populateContentView() { + // Profile picture view + let profilePictureView = ProfilePictureView() + let size = Values.largeProfilePictureSize + profilePictureView.size = size + profilePictureView.set(.width, to: size) + profilePictureView.set(.height, to: size) + profilePictureView.publicKey = sessionID + profilePictureView.update() + // Display name label + let displayNameLabel = UILabel() + let displayName = Storage.shared.getContact(with: sessionID)?.displayName(for: .regular) ?? sessionID + displayNameLabel.text = displayName + displayNameLabel.font = .boldSystemFont(ofSize: Values.largeFontSize) + displayNameLabel.textColor = Colors.text + displayNameLabel.numberOfLines = 1 + displayNameLabel.lineBreakMode = .byTruncatingTail + // Session ID label + let sessionIDLabel = UILabel() + sessionIDLabel.textColor = Colors.text + sessionIDLabel.font = Fonts.spaceMono(ofSize: isIPhone5OrSmaller ? Values.mediumFontSize : 20) + sessionIDLabel.numberOfLines = 0 + sessionIDLabel.lineBreakMode = .byCharWrapping + sessionIDLabel.accessibilityLabel = "Session ID label" + sessionIDLabel.text = sessionID + // Session ID label container + let sessionIDLabelContainer = UIView() + sessionIDLabelContainer.addSubview(sessionIDLabel) + sessionIDLabel.pin(to: sessionIDLabelContainer, withInset: Values.mediumSpacing) + sessionIDLabelContainer.layer.cornerRadius = TextField.cornerRadius + sessionIDLabelContainer.layer.borderWidth = 1 + sessionIDLabelContainer.layer.borderColor = isLightMode ? UIColor.black.cgColor : UIColor.white.cgColor + // Copy button + let copyButton = Button(style: .prominentOutline, size: .medium) + copyButton.setTitle(NSLocalizedString("copy", comment: ""), for: UIControl.State.normal) + copyButton.addTarget(self, action: #selector(copySessionID), for: UIControl.Event.touchUpInside) + copyButton.set(.width, to: 160) + // Stack view + let stackView = UIStackView(arrangedSubviews: [ profilePictureView, displayNameLabel, sessionIDLabelContainer, copyButton, UIView.vSpacer(Values.largeSpacing) ]) + stackView.axis = .vertical + stackView.spacing = Values.largeSpacing + stackView.alignment = .center + // Constraints + contentView.addSubview(stackView) + stackView.pin(to: contentView, withInset: Values.largeSpacing) + } + + @objc private func copySessionID() { + UIPasteboard.general.string = sessionID + presentingViewController?.dismiss(animated: true, completion: nil) + } +}