From e6b941ea8ad6babf69a966923f67b53ac83bedb4 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Mon, 28 Feb 2022 17:23:34 +1100 Subject: [PATCH] Fixed a number of tweaks and bugs with message requests Removed the "Back" text from the back buttons Removed the inset on the 'Path' settings button so the text remains horizontally centered Hid the settings button from message request threads Fixed an issue where the back button would remain visible in a conversation when the search field was visible Fixed an issue where the tintColor of the conversation search field didn't match the global search field Fixed an issue where sending an attachment response to a message request wouldn't approve the message request Updated the size and positioning of the message request 'Clear All' button to match the DM 'Next' button Updated the message request 'Clear All' button to start visible (so it's visible during the push animation) since that's the most likely state it'll be in Updated the 'Message Requests' cell to use the pinned background colour Updated the fallback for contact thread names to be a middle-truncated string (4 characters either side) --- .../ConversationVC+Interaction.swift | 68 ++++++++++++++----- Session/Conversations/ConversationVC.swift | 62 +++++++++++------ .../OWSConversationSettingsViewController.m | 18 +---- .../ConversationTitleView.swift | 10 ++- Session/Home/HomeVC.swift | 7 ++ .../MessageRequestsViewController.swift | 18 ++--- Session/Home/Views/MessageRequestsCell.swift | 2 +- Session/Settings/SettingsVC.swift | 4 +- Session/Shared/ConversationCell.swift | 15 ++-- SessionUIKit/Components/Button.swift | 5 +- .../UIViewController+Utilities.swift | 2 +- 11 files changed, 133 insertions(+), 78 deletions(-) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 33ef7e6dc..cec8846ca 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -10,6 +10,16 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc ConversationTitleViewDelegate { func handleTitleViewTapped() { + // Don't take the user to settings for message requests + guard + let contactThread: TSContactThread = thread as? TSContactThread, + let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()), + contact.isApproved, + contact.didApproveMe + else { + return + } + openSettings() } @@ -292,32 +302,56 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc func sendAttachments(_ attachments: [SignalAttachment], with text: String, onComplete: (() -> ())? = nil) { guard !showBlockedModalIfNeeded() else { return } + for attachment in attachments { if attachment.hasError { return showErrorAlert(for: attachment, onDismiss: onComplete) } } + let thread = self.thread + let sentTimestamp: UInt64 = NSDate.millisecondTimestamp() let message = VisibleMessage() - message.sentTimestamp = NSDate.millisecondTimestamp() + message.sentTimestamp = sentTimestamp message.text = replaceMentions(in: text) + + // Note: 'shouldBeVisible' is set to true the first time a thread is saved so we can + // use it to determine if the user is creating a new thread and update the 'isApproved' + // flags appropriately + let oldThreadShouldBeVisible: Bool = thread.shouldBeVisible let tsMessage = TSOutgoingMessage.from(message, associatedWith: thread) - Storage.write(with: { transaction in - tsMessage.save(with: transaction) - // The new message cell is inserted at this point, but the TSOutgoingMessage doesn't have its attachment yet - }, completion: { [weak self] in - Storage.write(with: { transaction in - MessageSender.send(message, with: attachments, in: thread, using: transaction) - }, completion: { [weak self] in - // At this point the TSOutgoingMessage should have its attachments set, so we can scroll to the bottom knowing - // the height of the new message cell - self?.scrollToBottom(isAnimated: false) - }) - self?.handleMessageSent() - - // Attachment successfully sent - dismiss the screen - onComplete?() - }) + + Storage.write( + with: { transaction in + tsMessage.save(with: transaction) + // The new message cell is inserted at this point, but the TSOutgoingMessage doesn't have its attachment yet + }, + completion: { [weak self] in + Storage.shared.write( + with: { transaction in + self?.approveMessageRequestIfNeeded( + for: self?.thread, + with: (transaction as! YapDatabaseReadWriteTransaction), + isNewThread: !oldThreadShouldBeVisible, + timestamp: (sentTimestamp - 1) // Set 1ms earlier as this is used for sorting + ) + }, + completion: { [weak self] in + Storage.write(with: { transaction in + MessageSender.send(message, with: attachments, in: thread, using: transaction) + }, completion: { [weak self] in + // At this point the TSOutgoingMessage should have its attachments set, so we can scroll to the bottom knowing + // the height of the new message cell + self?.scrollToBottom(isAnimated: false) + }) + self?.handleMessageSent() + + // Attachment successfully sent - dismiss the screen + onComplete?() + } + ) + } + ) } func handleMessageSent() { diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 932f2c434..f3fee082f 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -1,5 +1,6 @@ import SessionUIKit import SessionMessagingKit +import UIKit // TODO: // • Slight paging glitch when scrolling up and loading more content @@ -465,30 +466,53 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat // MARK: Updating func updateNavBarButtons() { + // Back button (to appear on pushed screen) + let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) + backButton.tintColor = Colors.text + navigationItem.backBarButtonItem = backButton + + navigationItem.hidesBackButton = isShowingSearchUI + if isShowingSearchUI { navigationItem.leftBarButtonItem = nil navigationItem.rightBarButtonItems = [] - } else { + } + else { + navigationItem.hidesBackButton = false navigationItem.leftBarButtonItem = UIViewController.createOWSBackButton(withTarget: self, selector: #selector(handleBackPressed)) - let rightBarButtonItem: UIBarButtonItem - if thread is TSContactThread { - let size = Values.verySmallProfilePictureSize - let profilePictureView = ProfilePictureView() - profilePictureView.accessibilityLabel = "Settings button" - profilePictureView.size = size - profilePictureView.update(for: thread) - profilePictureView.set(.width, to: size) - profilePictureView.set(.height, to: size) - let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings)) - profilePictureView.addGestureRecognizer(tapGestureRecognizer) - rightBarButtonItem = UIBarButtonItem(customView: profilePictureView) - } else { - rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings)) + if let contactThread: TSContactThread = thread as? TSContactThread { + // Don't show the settings button for message requests + if let contact: Contact = Storage.shared.getContact(with: contactThread.contactSessionID()), contact.isApproved, contact.didApproveMe { + let size = Values.verySmallProfilePictureSize + let profilePictureView = ProfilePictureView() + profilePictureView.size = size + profilePictureView.update(for: thread) + profilePictureView.set(.width, to: size) + profilePictureView.set(.height, to: size) + + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings)) + profilePictureView.addGestureRecognizer(tapGestureRecognizer) + + let rightBarButtonItem: UIBarButtonItem = UIBarButtonItem(customView: profilePictureView) + rightBarButtonItem.accessibilityLabel = "Settings button" + rightBarButtonItem.isAccessibilityElement = true + + navigationItem.rightBarButtonItem = rightBarButtonItem + } + else { + // Note: Adding an empty button because without it the title alignment is busted (Note: The size was + // taken from the layout inspector for the back button in Xcode + navigationItem.rightBarButtonItem = UIBarButtonItem(customView: UIView(frame: CGRect(x: 0, y: 0, width: 37, height: 44))) + } + } + else { + let rightBarButtonItem: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings)) + rightBarButtonItem.accessibilityLabel = "Settings button" + rightBarButtonItem.isAccessibilityElement = true + + navigationItem.rightBarButtonItem = rightBarButtonItem } - rightBarButtonItem.accessibilityLabel = "Settings button" - rightBarButtonItem.isAccessibilityElement = true - navigationItem.rightBarButtonItem = rightBarButtonItem } } @@ -819,7 +843,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat let searchBar = searchController.uiSearchController.searchBar searchBar.searchBarStyle = .minimal searchBar.barStyle = .black - searchBar.tintColor = Colors.accent + searchBar.tintColor = Colors.text let searchIcon = UIImage(named: "searchbar_search")!.asTintedImage(color: Colors.searchBarPlaceholder) searchBar.setImage(searchIcon, for: .search, state: UIControl.State.normal) let clearIcon = UIImage(named: "searchbar_clear")!.asTintedImage(color: Colors.searchBarPlaceholder) diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index 5585b155d..fcfb6d588 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -277,7 +277,7 @@ CGFloat kIconViewLength = 24; contents.title = NSLocalizedString(@"CONVERSATION_SETTINGS", @"title for conversation settings screen"); BOOL isNoteToSelf = self.thread.isNoteToSelf; - + __weak OWSConversationSettingsViewController *weakSelf = self; OWSTableSection *section = [OWSTableSection new]; @@ -332,7 +332,7 @@ CGFloat kIconViewLength = 24; } actionBlock:^{ [weakSelf tappedConversationSearch]; }]]; - + // Disappearing messages if (![self isOpenGroup]) { [section addItem:[OWSTableItem itemWithCustomCellBlock:^{ @@ -358,13 +358,6 @@ CGFloat kIconViewLength = 24; switchView.on = strongSelf.disappearingMessagesConfiguration.isEnabled; [switchView addTarget:strongSelf action:@selector(disappearingMessagesSwitchValueDidChange:) forControlEvents:UIControlEventValueChanged]; - - // Disable Disappearing Messages if the conversation hasn't been approved - if (!self.thread.isGroupThread) { - TSContactThread *thread = (TSContactThread *)self.thread; - SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID]; - [switchView setEnabled:(contact.isApproved && contact.didApproveMe)]; - } UIStackView *topRow = [[UIStackView alloc] initWithArrangedSubviews:@[ iconView, rowLabel, switchView ]]; @@ -438,13 +431,6 @@ CGFloat kIconViewLength = 24; [slider autoPinTrailingToSuperviewMargin]; [slider autoPinBottomToSuperviewMargin]; - // Disable Disappearing Messages slider if the conversation hasn't been approved (just in case) - if (!self.thread.isGroupThread) { - TSContactThread *thread = (TSContactThread *)self.thread; - SNContact *contact = [LKStorage.shared getContactWithSessionID:thread.contactSessionID]; - [slider setEnabled:(contact.isApproved && contact.didApproveMe)]; - } - cell.userInteractionEnabled = !strongSelf.hasLeftGroup; cell.accessibilityIdentifier = ACCESSIBILITY_IDENTIFIER_WITH_NAME( diff --git a/Session/Conversations/Views & Modals/ConversationTitleView.swift b/Session/Conversations/Views & Modals/ConversationTitleView.swift index d80912b29..a557e3666 100644 --- a/Session/Conversations/Views & Modals/ConversationTitleView.swift +++ b/Session/Conversations/Views & Modals/ConversationTitleView.swift @@ -73,13 +73,17 @@ final class ConversationTitleView : UIView { private func getTitle() -> String { if let thread = thread as? TSGroupThread { return thread.groupModel.groupName! - } else if thread.isNoteToSelf() { + } + else if thread.isNoteToSelf() { return "Note to Self" - } else { + } + else { let sessionID = (thread as! TSContactThread).contactSessionID() var result = sessionID Storage.read { transaction in - result = Storage.shared.getContact(with: sessionID)?.displayName(for: .regular) ?? "Anonymous" + let displayName: String = ((Storage.shared.getContact(with: sessionID)?.displayName(for: .regular)) ?? sessionID) + let middleTruncatedHexKey: String = "\(sessionID.prefix(4))...\(sessionID.suffix(4))" + result = (displayName == sessionID ? middleTruncatedHexKey : displayName) } return result } diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index f8635f167..01677bf05 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -393,11 +393,18 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv profilePictureViewContainer.addSubview(pathStatusView) pathStatusView.pin(.trailing, to: .trailing, of: profilePictureViewContainer) pathStatusView.pin(.bottom, to: .bottom, of: profilePictureViewContainer) + + // Back button (to appear on pushed screen) + let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) + backButton.tintColor = Colors.text + navigationItem.backBarButtonItem = backButton + // Left bar button item let leftBarButtonItem = UIBarButtonItem(customView: profilePictureViewContainer) leftBarButtonItem.accessibilityLabel = "Settings button" leftBarButtonItem.isAccessibilityElement = true navigationItem.leftBarButtonItem = leftBarButtonItem + // Right bar button item - search button let rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(showSearchUI)) rightBarButtonItem.accessibilityLabel = "Search button" diff --git a/Session/Home/Message Requests/MessageRequestsViewController.swift b/Session/Home/Message Requests/MessageRequestsViewController.swift index dfb4e1b73..32e1fc46e 100644 --- a/Session/Home/Message Requests/MessageRequestsViewController.swift +++ b/Session/Home/Message Requests/MessageRequestsViewController.swift @@ -63,23 +63,16 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat return result }() - private lazy var clearAllButton: UIButton = { - let result: UIButton = UIButton() + private lazy var clearAllButton: Button = { + let result: Button = Button(style: .destructiveOutline, size: .large) result.translatesAutoresizingMaskIntoConstraints = false - result.clipsToBounds = true - result.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18) result.setTitle(NSLocalizedString("MESSAGE_REQUESTS_CLEAR_ALL", comment: ""), for: .normal) - result.setTitleColor(Colors.destructive, for: .normal) result.setBackgroundImage( Colors.destructive .withAlphaComponent(isDarkMode ? 0.2 : 0.06) .toImage(isDarkMode: isDarkMode), for: .highlighted ) - result.isHidden = true - result.layer.cornerRadius = (NewConversationButtonSet.collapsedButtonSize / 2) - result.layer.borderColor = Colors.destructive.cgColor - result.layer.borderWidth = 1.5 result.addTarget(self, action: #selector(clearAllTapped), for: .touchUpInside) return result @@ -163,10 +156,11 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat clearAllButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), clearAllButton.bottomAnchor.constraint( - equalTo: view.bottomAnchor, - constant: -Values.newConversationButtonBottomOffset // Negative due to how the constraint is set up + equalTo: view.safeAreaLayoutGuide.bottomAnchor, + constant: -Values.largeSpacing ), - clearAllButton.widthAnchor.constraint(equalToConstant: 155), + // Note: The '182' is to match the 'Next' button on the New DM page (which doesn't have a fixed width) + clearAllButton.widthAnchor.constraint(equalToConstant: 182), clearAllButton.heightAnchor.constraint(equalToConstant: NewConversationButtonSet.collapsedButtonSize) ]) } diff --git a/Session/Home/Views/MessageRequestsCell.swift b/Session/Home/Views/MessageRequestsCell.swift index 5229a9540..54002f721 100644 --- a/Session/Home/Views/MessageRequestsCell.swift +++ b/Session/Home/Views/MessageRequestsCell.swift @@ -76,7 +76,7 @@ class MessageRequestsCell: UITableViewCell { }() private func setUpViewHierarchy() { - backgroundColor = Colors.cellBackground + backgroundColor = Colors.cellPinned selectedBackgroundView = UIView() selectedBackgroundView?.backgroundColor = Colors.cellSelected diff --git a/Session/Settings/SettingsVC.swift b/Session/Settings/SettingsVC.swift index 46be1b4d7..72228f5a8 100644 --- a/Session/Settings/SettingsVC.swift +++ b/Session/Settings/SettingsVC.swift @@ -139,7 +139,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { setUpNavBarStyle() setNavBarTitle(NSLocalizedString("vc_settings_title", comment: "")) // Navigation bar buttons - let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil) + let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) backButton.tintColor = Colors.text navigationItem.backBarButtonItem = backButton updateNavigationBarButtons() @@ -254,8 +254,6 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { pathStatusView.pin(.leading, to: .trailing, of: pathButton.titleLabel!, withInset: Values.smallSpacing) pathStatusView.autoVCenterInSuperview() - pathButton.titleEdgeInsets = UIEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: Values.smallSpacing) - return [ getSeparator(), pathButton, diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 3d56f4ecb..1e376ed3d 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -358,15 +358,20 @@ final class ConversationCell : UITableViewCell { if threadViewModel.isGroupThread { if threadViewModel.name.isEmpty { return "Unknown Group" - } else { + } + else { return threadViewModel.name } - } else { + } + else { if threadViewModel.threadRecord.isNoteToSelf() { return NSLocalizedString("NOTE_TO_SELF", comment: "") - } else { - let hexEncodedPublicKey = threadViewModel.contactSessionID! - return Storage.shared.getContact(with: hexEncodedPublicKey)?.displayName(for: .regular) ?? hexEncodedPublicKey + } + else { + let hexEncodedPublicKey: String = threadViewModel.contactSessionID! + let displayName: String = (Storage.shared.getContact(with: hexEncodedPublicKey)?.displayName(for: .regular) ?? hexEncodedPublicKey) + let middleTruncatedHexKey: String = "\(hexEncodedPublicKey.prefix(4))...\(hexEncodedPublicKey.suffix(4))" + return (displayName == hexEncodedPublicKey ? middleTruncatedHexKey : displayName) } } } diff --git a/SessionUIKit/Components/Button.swift b/SessionUIKit/Components/Button.swift index 93aaaf6f6..adb45f592 100644 --- a/SessionUIKit/Components/Button.swift +++ b/SessionUIKit/Components/Button.swift @@ -6,7 +6,7 @@ public final class Button : UIButton { private var heightConstraint: NSLayoutConstraint! public enum Style { - case unimportant, regular, prominentOutline, prominentFilled, regularBorderless + case unimportant, regular, prominentOutline, prominentFilled, regularBorderless, destructiveOutline } public enum Size { @@ -41,6 +41,7 @@ public final class Button : UIButton { case .prominentOutline: fillColor = UIColor.clear case .prominentFilled: fillColor = isLightMode ? Colors.text : Colors.accent case .regularBorderless: fillColor = UIColor.clear + case .destructiveOutline: fillColor = UIColor.clear } let borderColor: UIColor switch style { @@ -49,6 +50,7 @@ public final class Button : UIButton { case .prominentOutline: borderColor = isLightMode ? Colors.text : Colors.accent case .prominentFilled: borderColor = isLightMode ? Colors.text : Colors.accent case .regularBorderless: borderColor = UIColor.clear + case .destructiveOutline: borderColor = Colors.destructive } let textColor: UIColor switch style { @@ -57,6 +59,7 @@ public final class Button : UIButton { case .prominentOutline: textColor = isLightMode ? Colors.text : Colors.accent case .prominentFilled: textColor = isLightMode ? UIColor.white : Colors.text case .regularBorderless: textColor = Colors.text + case .destructiveOutline: textColor = Colors.destructive } let height: CGFloat switch size { diff --git a/SignalUtilitiesKit/Utilities/UIViewController+Utilities.swift b/SignalUtilitiesKit/Utilities/UIViewController+Utilities.swift index 582f9d38f..e5a0acb48 100644 --- a/SignalUtilitiesKit/Utilities/UIViewController+Utilities.swift +++ b/SignalUtilitiesKit/Utilities/UIViewController+Utilities.swift @@ -28,7 +28,7 @@ public final class ViewControllerUtilities : NSObject { } // Set up back button if hasCustomBackButton { - let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil) + let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) backButton.tintColor = Colors.text vc.navigationItem.backBarButtonItem = backButton }