From e73fe4fe31065c72530eff6fe354b7eeed488717 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 15 Mar 2022 14:34:22 +1100 Subject: [PATCH 01/13] bump up build number --- Session.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 0bab0b492..19150c39c 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5185,7 +5185,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 325; + CURRENT_PROJECT_VERSION = 327; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5258,7 +5258,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 325; + CURRENT_PROJECT_VERSION = 327; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5324,7 +5324,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 325; + CURRENT_PROJECT_VERSION = 327; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5398,7 +5398,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 325; + CURRENT_PROJECT_VERSION = 327; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6334,7 +6334,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 325; + CURRENT_PROJECT_VERSION = 327; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6405,7 +6405,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 325; + CURRENT_PROJECT_VERSION = 327; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 2e10ccf99d6c81a2399f62e8fafd100ac3131c3b Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 15 Mar 2022 16:06:53 +1100 Subject: [PATCH 02/13] Updated the code to cache the retrieval of the user public key --- Session.xcodeproj/project.pbxproj | 8 -------- Session/Settings/NukeDataModal.swift | 5 +++++ SessionMessagingKit/Meta/SessionMessagingKit.h | 1 - SessionMessagingKit/Utilities/General.swift | 18 ++++++++++++++++++ .../Utilities/GeneralUtilities.h | 11 ----------- .../Utilities/GeneralUtilities.m | 16 ---------------- .../NSENotificationPresenter.swift | 2 +- 7 files changed, 24 insertions(+), 37 deletions(-) delete mode 100644 SessionMessagingKit/Utilities/GeneralUtilities.h delete mode 100644 SessionMessagingKit/Utilities/GeneralUtilities.m diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 19150c39c..eec7f7dfa 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -241,8 +241,6 @@ B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; }; B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */; }; B8AE75A425A6C6A6001A84D2 /* Data+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */; }; - B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */; }; - B8AE761425ABFBB9001A84D2 /* GeneralUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8AF4BB426A5204600583500 /* SendSeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AF4BB326A5204600583500 /* SendSeedModal.swift */; }; B8B32021258B1A650020074B /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32020258B1A650020074B /* Contact.swift */; }; B8B32033258B235D0020074B /* Storage+Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32032258B235D0020074B /* Storage+Contacts.swift */; }; @@ -1249,8 +1247,6 @@ B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = ""; }; B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = ""; }; B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Trimming.swift"; sourceTree = ""; }; - B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneralUtilities.h; sourceTree = ""; }; - B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneralUtilities.m; sourceTree = ""; }; B8AF4BB326A5204600583500 /* SendSeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendSeedModal.swift; sourceTree = ""; }; B8B32020258B1A650020074B /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = ""; }; B8B32032258B235D0020074B /* Storage+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Contacts.swift"; sourceTree = ""; }; @@ -3225,8 +3221,6 @@ C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */, C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */, C33FDBC1255A581700E217F9 /* General.swift */, - B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */, - B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */, B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */, C3A71D0A2558989C0043A11F /* MessageWrapper.swift */, C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */, @@ -3789,7 +3783,6 @@ C32C5BF8256DC8F6003C73A2 /* OWSDisappearingMessagesJob.h in Headers */, C32C5AAA256DBE8F003C73A2 /* TSIncomingMessage.h in Headers */, B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */, - B8AE761425ABFBB9001A84D2 /* GeneralUtilities.h in Headers */, C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */, C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */, C3A3A193256E20D4004D228D /* SignalRecipient.h in Headers */, @@ -4782,7 +4775,6 @@ C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */, C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */, C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */, - B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */, C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */, C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */, B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */, diff --git a/Session/Settings/NukeDataModal.swift b/Session/Settings/NukeDataModal.swift index 7c86d629c..e3110969d 100644 --- a/Session/Settings/NukeDataModal.swift +++ b/Session/Settings/NukeDataModal.swift @@ -1,4 +1,7 @@ +import UIKit +import SessionUIKit import SessionSnodeKit +import SessionMessagingKit @objc(LKNukeDataModal) final class NukeDataModal : Modal { @@ -125,6 +128,7 @@ final class NukeDataModal : Modal { appDelegate.forceSyncConfigurationNowIfNeeded().ensure(on: DispatchQueue.main) { self?.dismiss(animated: true, completion: nil) // Dismiss the loader UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later + General.Cache.cachedEncodedPublicKey = nil // Remove the cached key so it gets re-cached on next access NotificationCenter.default.post(name: .dataNukeRequested, object: nil) }.retainUntilComplete() } @@ -136,6 +140,7 @@ final class NukeDataModal : Modal { self?.dismiss(animated: true, completion: nil) // Dismiss the loader let potentiallyMaliciousSnodes = confirmations.compactMap { $0.value == false ? $0.key : nil } if potentiallyMaliciousSnodes.isEmpty { + General.Cache.cachedEncodedPublicKey = nil // Remove the cached key so it gets re-cached on next access UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later NotificationCenter.default.post(name: .dataNukeRequested, object: nil) } else { diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index f989c52e6..498e820cb 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -5,7 +5,6 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import #import -#import #import #import #import diff --git a/SessionMessagingKit/Utilities/General.swift b/SessionMessagingKit/Utilities/General.swift index 62fee4eb1..565338f65 100644 --- a/SessionMessagingKit/Utilities/General.swift +++ b/SessionMessagingKit/Utilities/General.swift @@ -1,7 +1,25 @@ +import Foundation + +public enum General { + public enum Cache { + public static var cachedEncodedPublicKey: String? = nil + } +} + +@objc(SNGeneralUtilities) +public class GeneralUtilities: NSObject { + @objc public static func getUserPublicKey() -> String { + return getUserHexEncodedPublicKey() + } +} public func getUserHexEncodedPublicKey() -> String { + if let cachedKey: String = General.Cache.cachedEncodedPublicKey { return cachedKey } + if let keyPair = OWSIdentityManager.shared().identityKeyPair() { // Can be nil under some circumstances + General.Cache.cachedEncodedPublicKey = keyPair.hexEncodedPublicKey return keyPair.hexEncodedPublicKey } + return "" } diff --git a/SessionMessagingKit/Utilities/GeneralUtilities.h b/SessionMessagingKit/Utilities/GeneralUtilities.h deleted file mode 100644 index cb120b993..000000000 --- a/SessionMessagingKit/Utilities/GeneralUtilities.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface SNGeneralUtilities : NSObject - -+ (NSString *)getUserPublicKey; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SessionMessagingKit/Utilities/GeneralUtilities.m b/SessionMessagingKit/Utilities/GeneralUtilities.m deleted file mode 100644 index 777a6c3fd..000000000 --- a/SessionMessagingKit/Utilities/GeneralUtilities.m +++ /dev/null @@ -1,16 +0,0 @@ -#import -#import "GeneralUtilities.h" -#import "OWSIdentityManager.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation SNGeneralUtilities - -+ (NSString *)getUserPublicKey -{ - return OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SessionNotificationServiceExtension/NSENotificationPresenter.swift b/SessionNotificationServiceExtension/NSENotificationPresenter.swift index 6e330b94a..a9aab1e44 100644 --- a/SessionNotificationServiceExtension/NSENotificationPresenter.swift +++ b/SessionNotificationServiceExtension/NSENotificationPresenter.swift @@ -28,7 +28,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol { } let senderPublicKey = incomingMessage.authorId - let userPublicKey = SNGeneralUtilities.getUserPublicKey() + let userPublicKey = GeneralUtilities.getUserPublicKey() guard senderPublicKey != userPublicKey else { // Ignore PNs for messages sent by the current user // after handling the message. Otherwise the closed From 22e5352983b33c17ecda65bbc474fbb7a20249ab Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 15 Mar 2022 16:35:38 +1100 Subject: [PATCH 03/13] Swapped a number of areas to use the built-in tintColor instead of the custom asTintedImage --- .../Message Cells/VisibleMessageCell.swift | 34 +++++++++++++------ Session/Shared/ConversationCell.swift | 29 +++++++++++----- Session/Shared/UserCell.swift | 22 +++++++----- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index bbcd2679a..114bf34b0 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -254,8 +254,9 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { let authorLabelSize = authorLabel.sizeThatFits(authorLabelAvailableSpace) authorLabelHeightConstraint.constant = (viewItem.senderName != nil) ? authorLabelSize.height : 0 // Message status image view - let (image, backgroundColor) = getMessageStatusImage(for: message) + let (image, tintColor, backgroundColor) = getMessageStatusImage(for: message) messageStatusImageView.image = image + messageStatusImageView.tintColor = tintColor messageStatusImageView.backgroundColor = backgroundColor if let message = message as? TSOutgoingMessage { messageStatusImageView.isHidden = (message.messageState == .sent && thread?.lastInteraction != message) @@ -612,20 +613,33 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { } } - private func getMessageStatusImage(for message: TSMessage) -> (image: UIImage?, backgroundColor: UIColor?) { - guard let message = message as? TSOutgoingMessage else { return (nil, nil) } + private func getMessageStatusImage(for message: TSMessage) -> (image: UIImage?, tintColor: UIColor?, backgroundColor: UIColor?) { + guard let message = message as? TSOutgoingMessage else { return (nil, nil, nil) } + let image: UIImage + var tintColor: UIColor? = nil var backgroundColor: UIColor? = nil let status = MessageRecipientStatusUtils.recipientStatus(outgoingMessage: message) + switch status { - case .uploading, .sending: image = #imageLiteral(resourceName: "CircleDotDotDot").asTintedImage(color: Colors.text)! - case .sent, .skipped, .delivered: image = #imageLiteral(resourceName: "CircleCheck").asTintedImage(color: Colors.text)! - 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.destructive)! + case .uploading, .sending: + image = #imageLiteral(resourceName: "CircleDotDotDot").withRenderingMode(.alwaysTemplate) + tintColor = Colors.text + + case .sent, .skipped, .delivered: + image = #imageLiteral(resourceName: "CircleCheck").withRenderingMode(.alwaysTemplate) + tintColor = Colors.text + + case .read: + image = isLightMode ? #imageLiteral(resourceName: "FilledCircleCheckLightMode") : #imageLiteral(resourceName: "FilledCircleCheckDarkMode") + backgroundColor = isLightMode ? .black : .white + + case .failed: + image = #imageLiteral(resourceName: "message_status_failed").withRenderingMode(.alwaysTemplate) + tintColor = Colors.destructive } - return (image, backgroundColor) + + return (image, tintColor, backgroundColor) } private func getSize(for viewItem: ConversationViewItem) -> CGSize { diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 760b2326f..152a442c3 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -321,19 +321,30 @@ final class ConversationCell : UITableViewCell { statusIndicatorView.backgroundColor = nil let lastMessage = threadViewModel.lastMessageForInbox if let lastMessage = lastMessage as? TSOutgoingMessage { - let image: UIImage let status = MessageRecipientStatusUtils.recipientStatus(outgoingMessage: lastMessage) + switch status { - case .uploading, .sending: image = #imageLiteral(resourceName: "CircleDotDotDot").asTintedImage(color: Colors.text)! - case .sent, .skipped, .delivered: image = #imageLiteral(resourceName: "CircleCheck").asTintedImage(color: Colors.text)! - case .read: - statusIndicatorView.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 .uploading, .sending: + statusIndicatorView.image = #imageLiteral(resourceName: "CircleDotDotDot").withRenderingMode(.alwaysTemplate) + statusIndicatorView.tintColor = Colors.text + + case .sent, .skipped, .delivered: + statusIndicatorView.image = #imageLiteral(resourceName: "CircleCheck").withRenderingMode(.alwaysTemplate) + statusIndicatorView.tintColor = Colors.text + + case .read: + statusIndicatorView.image = isLightMode ? #imageLiteral(resourceName: "FilledCircleCheckLightMode") : #imageLiteral(resourceName: "FilledCircleCheckDarkMode") + statusIndicatorView.tintColor = nil + statusIndicatorView.backgroundColor = (isLightMode ? .black : .white) + + case .failed: + statusIndicatorView.image = #imageLiteral(resourceName: "message_status_failed").withRenderingMode(.alwaysTemplate) + statusIndicatorView.tintColor = Colors.destructive } - statusIndicatorView.image = image + statusIndicatorView.isHidden = false - } else { + } + else { statusIndicatorView.isHidden = true } } diff --git a/Session/Shared/UserCell.swift b/Session/Shared/UserCell.swift index fb493fc5d..8fd199a28 100644 --- a/Session/Shared/UserCell.swift +++ b/Session/Shared/UserCell.swift @@ -83,16 +83,22 @@ final class UserCell : UITableViewCell { profilePictureView.publicKey = publicKey profilePictureView.update() displayNameLabel.text = Storage.shared.getContact(with: publicKey)?.displayName(for: .regular) ?? publicKey + switch accessory { - case .none: accessoryImageView.isHidden = true - case .lock: - accessoryImageView.isHidden = false - accessoryImageView.image = #imageLiteral(resourceName: "ic_lock_outline").asTintedImage(color: Colors.text.withAlphaComponent(Values.mediumOpacity))! - case .tick(let isSelected): - accessoryImageView.isHidden = false - let icon = isSelected ? #imageLiteral(resourceName: "CircleCheck") : #imageLiteral(resourceName: "Circle") - accessoryImageView.image = isDarkMode ? icon : icon.asTintedImage(color: Colors.text)! + case .none: accessoryImageView.isHidden = true + + case .lock: + accessoryImageView.isHidden = false + accessoryImageView.image = #imageLiteral(resourceName: "ic_lock_outline").withRenderingMode(.alwaysTemplate) + accessoryImageView.tintColor = Colors.text.withAlphaComponent(Values.mediumOpacity) + + case .tick(let isSelected): + let icon: UIImage = (isSelected ? #imageLiteral(resourceName: "CircleCheck") : #imageLiteral(resourceName: "Circle")) + accessoryImageView.isHidden = false + accessoryImageView.image = icon.withRenderingMode(.alwaysTemplate) + accessoryImageView.tintColor = Colors.text } + let alpha: CGFloat = isZombie ? 0.5 : 1 [ profilePictureView, displayNameLabel, accessoryImageView ].forEach { $0.alpha = alpha } } From 07658b88939bc228364ea8335db4101b043143a0 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 16 Mar 2022 11:41:30 +1100 Subject: [PATCH 04/13] Changed the labels on the conversation menu items to be bold --- Session/Home/NewConversationButtonSet.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Session/Home/NewConversationButtonSet.swift b/Session/Home/NewConversationButtonSet.swift index d0a82def5..b1f933479 100644 --- a/Session/Home/NewConversationButtonSet.swift +++ b/Session/Home/NewConversationButtonSet.swift @@ -25,7 +25,7 @@ final class NewConversationButtonSet : UIView { private lazy var newDMLabel: UILabel = { let result: UILabel = UILabel() result.translatesAutoresizingMaskIntoConstraints = false - result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize) + result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize, weight: .bold) result.text = NSLocalizedString("NEW_CONVERSATION_MENU_DIRECT_MESSAGE", comment: "").uppercased() result.textColor = Colors.grey result.textAlignment = .center @@ -36,7 +36,7 @@ final class NewConversationButtonSet : UIView { private lazy var createClosedGroupLabel: UILabel = { let result: UILabel = UILabel() result.translatesAutoresizingMaskIntoConstraints = false - result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize) + result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize, weight: .bold) result.text = NSLocalizedString("NEW_CONVERSATION_MENU_CLOSED_GROUP", comment: "").uppercased() result.textColor = Colors.grey result.textAlignment = .center @@ -47,7 +47,7 @@ final class NewConversationButtonSet : UIView { private lazy var joinOpenGroupLabel: UILabel = { let result: UILabel = UILabel() result.translatesAutoresizingMaskIntoConstraints = false - result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize) + result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize, weight: .bold) result.text = NSLocalizedString("NEW_CONVERSATION_MENU_OPEN_GROUP", comment: "").uppercased() result.textColor = Colors.grey result.textAlignment = .center From 6bc0177bd45cedd716f755ff2749e08e990af19c Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 17 Mar 2022 10:13:00 +1100 Subject: [PATCH 05/13] fix path building crash --- SessionSnodeKit/OnionRequestAPI.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 61e617c72..7a03b16f0 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -204,7 +204,11 @@ public enum OnionRequestAPI { } else { return buildPaths(reusing: []).map2 { paths in if let snode = snode { - return paths.filter { !$0.contains(snode) }.randomElement()! + if let path = paths.filter({ !$0.contains(snode) }).randomElement() { + return path + } else { + throw Error.insufficientSnodes + } } else { return paths.randomElement()! } From 95797d427c4cc6217f55f296c98fff813900fcf5 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 17 Mar 2022 10:43:11 +1100 Subject: [PATCH 06/13] fix link preview text colour --- .../Message Cells/Content Views/LinkPreviewView.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift index a9bd6f3c5..f6ef16991 100644 --- a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift +++ b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift @@ -12,6 +12,7 @@ final class LinkPreviewView : UIView { let isOutgoing = (viewItem!.interaction.interactionType() == .outgoingMessage) switch (isOutgoing, AppModeManager.shared.currentAppMode) { case (true, .dark), (false, .light): return .black + case (true, .light): return Colors.grey default: return .white } }() @@ -133,15 +134,7 @@ final class LinkPreviewView : UIView { loader.alpha = (image != nil) ? 0 : 1 if image != nil { loader.stopAnimating() } else { loader.startAnimating() } // Title - let isSent = (linkPreviewState is LinkPreviewSent) - let isOutgoing = (viewItem?.interaction.interactionType() == .outgoingMessage) - let textColor: UIColor - if isSent && isOutgoing && isLightMode { - textColor = .white - } else { - textColor = isDarkMode ? .white : .black - } - titleLabel.textColor = textColor + titleLabel.textColor = sentLinkPreviewTextColor titleLabel.text = linkPreviewState.title() // Horizontal stack view switch linkPreviewState { From d4c0acb2a7cb4cd6312f0ee8f58c9b70e29aa0f7 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Thu, 17 Mar 2022 14:17:33 +1100 Subject: [PATCH 07/13] Updated the configuration message to sync the blocked state correctly --- .../Control Messages/ConfigurationMessage+Convenience.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift index ad1e6979b..d08ef570e 100644 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift +++ b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift @@ -82,7 +82,7 @@ extension ConfigurationMessage { hasIsApproved: true, isApproved: contact.isApproved, hasIsBlocked: true, - isBlocked: contact.isBlocked, + isBlocked: SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID), hasDidApproveMe: true, didApproveMe: contact.didApproveMe ) From 81317db165795cf6821a0713e770b852b86dd8bb Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 17 Mar 2022 15:48:33 +1100 Subject: [PATCH 08/13] fix message with two links and a link preview, second link uses address of first --- Session/Conversations/ConversationVC+Interaction.swift | 5 +---- .../Message Cells/Content Views/LinkPreviewView.swift | 3 +++ Session/Conversations/Message Cells/VisibleMessageCell.swift | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 48031c38d..cc41b44e4 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -590,10 +590,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc navigationController!.present(shareVC, animated: true, completion: nil) } case .textOnlyMessage: - if let preview = viewItem.linkPreview, let urlAsString = preview.urlString, let url = URL(string: urlAsString) { - // Open the link preview URL - openURL(url) - } else if let reply = viewItem.quotedReply { + if let reply = viewItem.quotedReply { // Scroll to the source of the reply guard let indexPath = viewModel.ensureLoadWindowContainsQuotedReply(reply) else { return } messagesTableView.scrollToRow(at: indexPath, at: UITableView.ScrollPosition.middle, animated: true) diff --git a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift index f6ef16991..a2fe25fc5 100644 --- a/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift +++ b/Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift @@ -58,6 +58,8 @@ final class LinkPreviewView : UIView { result.addTarget(self, action: #selector(cancel), for: UIControl.Event.touchUpInside) return result }() + + var bodyTextView: UITextView? // MARK: Settings private static let loaderSize: CGFloat = 24 @@ -145,6 +147,7 @@ final class LinkPreviewView : UIView { bodyTextViewContainer.subviews.forEach { $0.removeFromSuperview() } if let viewItem = viewItem { let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: sentLinkPreviewTextColor, searchText: delegate.lastSearchedText, delegate: delegate) + self.bodyTextView = bodyTextView bodyTextViewContainer.addSubview(bodyTextView) bodyTextView.pin(to: bodyTextViewContainer, withInset: 12) } diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index bbcd2679a..22e4f8a2a 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -324,6 +324,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { snContentView.addSubview(linkPreviewView) linkPreviewView.pin(to: snContentView) linkPreviewView.layer.mask = bubbleViewMaskLayer + self.bodyTextView = linkPreviewView.bodyTextView } else if let openGroupInvitationName = message.openGroupInvitationName, let openGroupInvitationURL = message.openGroupInvitationURL { let openGroupInvitationView = OpenGroupInvitationView(name: openGroupInvitationName, url: openGroupInvitationURL, textColor: bodyLabelTextColor, isOutgoing: isOutgoing) snContentView.addSubview(openGroupInvitationView) From 7fb6726d43da131e08cecbc959076710e2fc010f Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 17 Mar 2022 16:08:45 +1100 Subject: [PATCH 09/13] refactor on media+text message cell --- Session.xcodeproj/project.pbxproj | 4 - .../ConversationVC+Interaction.swift | 9 +-- .../Content Views/MediaTextOverlayView.swift | 74 ------------------- .../Message Cells/VisibleMessageCell.swift | 13 ++-- 4 files changed, 7 insertions(+), 93 deletions(-) delete mode 100644 Session/Conversations/Message Cells/Content Views/MediaTextOverlayView.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 19150c39c..405c2d94b 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -196,7 +196,6 @@ B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2D1255B6DAF007E1867 /* OWSUserProfile.m */; }; B8566C7D256F62030045A0B9 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2D3255B6DAF007E1867 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8569AC325CB5D2900DBA3DB /* ConversationVC+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AC225CB5D2900DBA3DB /* ConversationVC+Interaction.swift */; }; - B8569AD325CBA13D00DBA3DB /* MediaTextOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AD225CBA13D00DBA3DB /* MediaTextOverlayView.swift */; }; B8569AE325CBB19A00DBA3DB /* DocumentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AE225CBB19A00DBA3DB /* DocumentView.swift */; }; B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; }; B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; @@ -1226,7 +1225,6 @@ B8544E3223D50E4900299F14 /* SNAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SNAppearance.swift; sourceTree = ""; }; B8566C62256F55930045A0B9 /* OWSLinkPreview+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OWSLinkPreview+Conversion.swift"; sourceTree = ""; }; B8569AC225CB5D2900DBA3DB /* ConversationVC+Interaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConversationVC+Interaction.swift"; sourceTree = ""; }; - B8569AD225CBA13D00DBA3DB /* MediaTextOverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaTextOverlayView.swift; sourceTree = ""; }; B8569AE225CBB19A00DBA3DB /* DocumentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentView.swift; sourceTree = ""; }; B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; B86BD08523399CEF000F5AE3 /* SeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedModal.swift; sourceTree = ""; }; @@ -2175,7 +2173,6 @@ isa = PBXGroup; children = ( 34A8B3502190A40E00218A25 /* MediaAlbumView.swift */, - B8569AD225CBA13D00DBA3DB /* MediaTextOverlayView.swift */, 3488F9352191CC4000E524CC /* MediaView.swift */, B8041A9425C8FA1D003C2166 /* MediaLoaderView.swift */, B8F5F71925F1B35C003BF8D4 /* MediaPlaceholderView.swift */, @@ -4949,7 +4946,6 @@ 341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */, 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */, 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 */, diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index cc41b44e4..7e3aec685 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -544,14 +544,7 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc } else { guard let albumView = cell.albumView else { return } let locationInCell = gestureRecognizer.location(in: cell) - // Figure out whether the "read more" button was tapped - if let overlayView = cell.mediaTextOverlayView { - let locationInOverlayView = cell.convert(locationInCell, to: overlayView) - if let readMoreButton = overlayView.readMoreButton, readMoreButton.frame.contains(locationInOverlayView) { - return showFullText(viewItem) // HACK: This is a dirty way to do this - } - } - // Otherwise, figure out which of the media views was tapped + // Figure out which of the media views was tapped let locationInAlbumView = cell.convert(locationInCell, to: albumView) guard let mediaView = albumView.mediaView(forLocation: locationInAlbumView) else { return } if albumView.isMoreItemsView(mediaView: mediaView) && viewItem.mediaAlbumHasFailedAttachment() { diff --git a/Session/Conversations/Message Cells/Content Views/MediaTextOverlayView.swift b/Session/Conversations/Message Cells/Content Views/MediaTextOverlayView.swift deleted file mode 100644 index a0c655a5f..000000000 --- a/Session/Conversations/Message Cells/Content Views/MediaTextOverlayView.swift +++ /dev/null @@ -1,74 +0,0 @@ -import UIKit - -/// Shown over a media message if it has a message body. -final class MediaTextOverlayView : UIView { - private let viewItem: ConversationViewItem - private let albumViewWidth: CGFloat - private let delegate: MessageCellDelegate - private let textColor: UIColor - var readMoreButton: UIButton? - - // MARK: Settings - private static let maxHeight: CGFloat = 88; - - // MARK: Lifecycle - init(viewItem: ConversationViewItem, albumViewWidth: CGFloat, textColor: UIColor, delegate: MessageCellDelegate) { - self.viewItem = viewItem - self.albumViewWidth = albumViewWidth - self.delegate = delegate - self.textColor = textColor - super.init(frame: CGRect.zero) - setUpViewHierarchy() - } - - override init(frame: CGRect) { - preconditionFailure("Use init(text:) instead.") - } - - required init?(coder: NSCoder) { - preconditionFailure("Use init(text:) instead.") - } - - private func setUpViewHierarchy() { - guard let message = viewItem.interaction as? TSMessage, let body = message.body, body.count > 0 else { return } - // Body label - let bodyLabel = UILabel() - bodyLabel.numberOfLines = 0 - bodyLabel.lineBreakMode = .byTruncatingTail - bodyLabel.text = given(body) { MentionUtilities.highlightMentions(in: $0, threadID: viewItem.interaction.uniqueThreadId) } - bodyLabel.textColor = self.textColor - bodyLabel.font = .systemFont(ofSize: Values.mediumFontSize) - // Content stack view - let contentStackView = UIStackView(arrangedSubviews: [ bodyLabel ]) - contentStackView.axis = .horizontal - contentStackView.spacing = Values.smallSpacing - addSubview(contentStackView) - let inset: CGFloat = 12 - contentStackView.pin(.left, to: .left, of: self, withInset: inset) - contentStackView.pin(.top, to: .top, of: self) - contentStackView.pin(.right, to: .right, of: self, withInset: -inset) - // Max height - bodyLabel.heightAnchor.constraint(lessThanOrEqualToConstant: MediaTextOverlayView.maxHeight).isActive = true - // Overflow button - let bodyLabelTargetSize = bodyLabel.sizeThatFits(CGSize(width: albumViewWidth - 2 * inset, height: .greatestFiniteMagnitude)) - if bodyLabelTargetSize.height > MediaTextOverlayView.maxHeight { - let readMoreButton = UIButton() - self.readMoreButton = readMoreButton - readMoreButton.setTitle("Read More", for: UIControl.State.normal) - readMoreButton.titleLabel!.font = .boldSystemFont(ofSize: Values.smallFontSize) - readMoreButton.setTitleColor(self.textColor, for: UIControl.State.normal) - readMoreButton.addTarget(self, action: #selector(readMore), for: UIControl.Event.touchUpInside) - addSubview(readMoreButton) - readMoreButton.pin(.left, to: .left, of: self, withInset: inset) - readMoreButton.pin(.top, to: .bottom, of: contentStackView, withInset: Values.smallSpacing) - readMoreButton.pin(.bottom, to: .bottom, of: self, withInset: -Values.smallSpacing) - } else { - contentStackView.pin(.bottom, to: .bottom, of: self, withInset: -inset) - } - } - - // MARK: Interaction - @objc private func readMore() { - delegate.showFullText(viewItem) - } -} diff --git a/Session/Conversations/Message Cells/VisibleMessageCell.swift b/Session/Conversations/Message Cells/VisibleMessageCell.swift index 22e4f8a2a..a707858e3 100644 --- a/Session/Conversations/Message Cells/VisibleMessageCell.swift +++ b/Session/Conversations/Message Cells/VisibleMessageCell.swift @@ -4,7 +4,6 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { private var previousX: CGFloat = 0 var albumView: MediaAlbumView? var bodyTextView: UITextView? - var mediaTextOverlayView: MediaTextOverlayView? // Constraints private lazy var headerViewTopConstraint = headerView.pin(.top, to: .top, of: self, withInset: 1) private lazy var authorLabelHeightConstraint = authorLabel.set(.height, to: 0) @@ -312,7 +311,6 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { } albumView = nil bodyTextView = nil - mediaTextOverlayView = nil let isOutgoing = (viewItem.interaction.interactionType() == .outgoingMessage) switch viewItem.messageCellType { case .textOnlyMessage: @@ -373,11 +371,12 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate { albumView.layer.mask = bubbleViewMaskLayer stackView.addArrangedSubview(albumView) // Body text view - if let message = viewItem.interaction as? TSMessage, let body = message.body, body.count > 0, - let delegate = delegate { // delegate should always be set at this point - let overlayView = MediaTextOverlayView(viewItem: viewItem, albumViewWidth: size.width, textColor: bodyLabelTextColor, delegate: delegate) - self.mediaTextOverlayView = overlayView - stackView.addArrangedSubview(overlayView) + if let message = viewItem.interaction as? TSMessage, let body = message.body, body.count > 0 { + let inset: CGFloat = 12 + let maxWidth = size.width - 2 * inset + let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: bodyLabelTextColor, searchText: delegate?.lastSearchedText, delegate: self) + self.bodyTextView = bodyTextView + stackView.addArrangedSubview(UIView(wrapping: bodyTextView, withInsets: UIEdgeInsets(top: 0, left: inset, bottom: inset, right: inset))) } unloadContent = { albumView.unloadMedia() } // Constraints From 452614d1901499f0da92fcf69f87cc9b55432ebd Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Fri, 18 Mar 2022 10:20:59 +1100 Subject: [PATCH 10/13] Fixed a bug where the OpenGroup url parsing wasn't working for a certain URL structure --- SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift b/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift index 1e57471bf..9a1b67df9 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift @@ -126,7 +126,10 @@ public final class OpenGroupManagerV2 : NSObject { // https://143.198.213.225:443/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c // 143.198.213.255:80/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c let useTLS = (url.scheme == "https") - let updatedPath = (url.path.starts(with: "/r/") ? url.path.substring(from: 2) : url.path) + + // If there is no scheme then the host is included in the path (so handle that case) + let hostFreePath = (url.host != nil || !url.path.starts(with: host) ? url.path : url.path.substring(from: host.count)) + let updatedPath = (hostFreePath.starts(with: "/r/") ? hostFreePath.substring(from: 2) : hostFreePath) let room = String(updatedPath.dropFirst()) // Drop the leading slash let queryParts = query.split(separator: "=") guard !room.isEmpty && !room.contains("/"), queryParts.count == 2, queryParts[0] == "public_key" else { return nil } From d3b54b84d0f4c83b75cfac48af9f705dd8ee0a9f Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Mon, 21 Mar 2022 13:52:18 +1100 Subject: [PATCH 11/13] Prevent the user from joining duplicate open groups due to url differences Updated the OpenGroupManagerV2 to handle HTTP scheme variants and official host variants when checking if the user is already in an open group --- .../Open Groups/OpenGroupAPIV2.swift | 1 + .../Open Groups/OpenGroupManagerV2.swift | 45 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPIV2.swift b/SessionMessagingKit/Open Groups/OpenGroupAPIV2.swift index 481fcdfd0..d8206b604 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPIV2.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPIV2.swift @@ -18,6 +18,7 @@ public final class OpenGroupAPIV2 : NSObject { }() // MARK: Settings + public static let legacyDefaultServerDNS = "open.getsession.org" public static let defaultServer = "http://116.203.70.33" public static let defaultServerPublicKey = "a03c383cf63c3c4efe67acc52112a6dd734b3a946b9545f488aaa93da7991238" diff --git a/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift b/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift index 1e57471bf..04d36c875 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift @@ -29,12 +29,51 @@ public final class OpenGroupManagerV2 : NSObject { } // MARK: Adding & Removing + + public func hasExistingOpenGroup(room: String, server: String, publicKey: String, using transaction: YapDatabaseReadWriteTransaction) -> Bool { + let schemeFreeServer: String = (server.starts(with: "https://") ? server.substring(from: "https://".count) : server.substring(from: "http://".count)) + let schemeFreeDefaultServer: String = OpenGroupAPIV2.defaultServer.substring(from: "http://".count) + var serverOptions: Set = Set([ + schemeFreeServer, + "http://\(schemeFreeServer)", + "https://\(schemeFreeServer)" + ]) + + if schemeFreeServer == OpenGroupAPIV2.legacyDefaultServerDNS { + let defaultServerOptions: Set = Set([ + schemeFreeDefaultServer, + OpenGroupAPIV2.defaultServer, + "https://\(schemeFreeDefaultServer)" + ]) + serverOptions = serverOptions.union(defaultServerOptions) + } + else if schemeFreeServer == schemeFreeDefaultServer { + let legacyServerOptions: Set = Set([ + OpenGroupAPIV2.legacyDefaultServerDNS, + "http://\(OpenGroupAPIV2.legacyDefaultServerDNS)", + "https://\(OpenGroupAPIV2.legacyDefaultServerDNS)" + ]) + serverOptions = serverOptions.union(legacyServerOptions) + } + + // First check if there is an existing poller for the given server options + guard serverOptions.first(where: { OpenGroupManagerV2.shared.pollers[$0] != nil }) == nil else { return true } + + // Then check if there is an existing open group thread + let hasExistingThread: Bool = serverOptions.contains(where: { serverName in + let groupId: Data = LKGroupUtilities.getEncodedOpenGroupIDAsData("\(serverName).\(room)") + + return (TSGroupThread.fetch(groupId: groupId, transaction: transaction) != nil) + }) + + return hasExistingThread + } + public func add(room: String, server: String, publicKey: String, using transaction: Any) -> Promise { // If we are currently polling for this server and already have a TSGroupThread for this room the do nothing let transaction = transaction as! YapDatabaseReadWriteTransaction - let groupId: Data = LKGroupUtilities.getEncodedOpenGroupIDAsData("\(server).\(room)") - - if OpenGroupManagerV2.shared.pollers[server] != nil && TSGroupThread.fetch(groupId: groupId, transaction: transaction) != nil { + + if hasExistingOpenGroup(room: room, server: server, publicKey: publicKey, using: transaction) { SNLog("Ignoring join open group attempt (already joined)") return Promise.value(()) } From 8652268557f3393f8c639322f335dbb3fc8cc83a Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Mon, 21 Mar 2022 13:55:51 +1100 Subject: [PATCH 12/13] add logs & fix PN --- Session/Shared/BaseVC.swift | 3 +++ .../Pollers/OpenGroupPollerV2.swift | 1 + .../NSENotificationPresenter.swift | 20 +++++++++++++------ .../NotificationServiceExtension.swift | 5 ++++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Session/Shared/BaseVC.swift b/Session/Shared/BaseVC.swift index b2953ed36..0bccafb10 100644 --- a/Session/Shared/BaseVC.swift +++ b/Session/Shared/BaseVC.swift @@ -106,6 +106,9 @@ class BaseVC : UIViewController { } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + if #available(iOS 13.0, *) { + SNLog("Current trait collection: \(UITraitCollection.current), previous trait collection: \(previousTraitCollection)") + } if LKAppModeUtilities.isSystemDefault { NotificationCenter.default.post(name: .appModeChanged, object: nil) } diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift index 4c2ddbc8a..a1b3a47b3 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift @@ -48,6 +48,7 @@ public final class OpenGroupPollerV2 : NSObject { guard let self = self else { return } self.isPolling = false bodies.forEach { self.handleCompactPollBody($0, isBackgroundPoll: isBackgroundPoll) } + SNLog("Open group polling finished for \(self.server).") seal.fulfill(()) }.catch(on: OpenGroupAPIV2.workQueue) { error in SNLog("Open group polling failed due to error: \(error).") diff --git a/SessionNotificationServiceExtension/NSENotificationPresenter.swift b/SessionNotificationServiceExtension/NSENotificationPresenter.swift index 6e330b94a..836f54556 100644 --- a/SessionNotificationServiceExtension/NSENotificationPresenter.swift +++ b/SessionNotificationServiceExtension/NSENotificationPresenter.swift @@ -13,14 +13,14 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol { // to check if this is the only message request thread (group threads can't be message requests // so just ignore those and if the user has hidden message requests then we want to show the // notification regardless of how many message requests there are) - if !thread.isGroupThread() && thread.isMessageRequest() && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] { + if !thread.isGroupThread() && thread.isMessageRequest(using: transaction) && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] { let threads = transaction.ext(TSThreadDatabaseViewExtensionName) as! YapDatabaseViewTransaction let numMessageRequests = threads.numberOfItems(inGroup: TSMessageRequestGroup) // Allow this to show a notification if there are no message requests (ie. this is the first one) guard numMessageRequests == 0 else { return } } - else if thread.isMessageRequest() && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] { + else if thread.isMessageRequest(using: transaction) && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] { // If there are other interactions on this thread already then don't show the notification if thread.numberOfInteractions(with: transaction) > 1 { return } @@ -37,7 +37,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol { } let context = Contact.context(for: thread) - let senderName = Storage.shared.getContact(with: senderPublicKey)?.displayName(for: context) ?? senderPublicKey + let senderName = Storage.shared.getContact(with: senderPublicKey, using: transaction)?.displayName(for: context) ?? senderPublicKey var notificationTitle = senderName if let group = thread as? TSGroupThread { @@ -85,7 +85,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol { // If it's a message request then overwrite the body to be something generic (only show a notification // when receiving a new message request if there aren't any others or the user had hidden them) - if thread.isMessageRequest() { + if thread.isMessageRequest(using: transaction) { notificationContent.title = "Session" notificationContent.body = "MESSAGE_REQUESTS_NOTIFICATION".localized() } @@ -93,8 +93,16 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol { // Add request let identifier = incomingMessage.notificationIdentifier ?? UUID().uuidString let request = UNNotificationRequest(identifier: identifier, content: notificationContent, trigger: nil) - SNLog("Add remote notification request") - UNUserNotificationCenter.current().add(request) + SNLog("Add remote notification request: \(notificationContent.body)") + let semaphore = DispatchSemaphore(value: 0) + UNUserNotificationCenter.current().add(request) { error in + if let error = error { + SNLog("Failed to add notification request due to error:\(error)") + } + semaphore.signal() + } + semaphore.wait() + SNLog("Finish adding remote notification request") } public func cancelNotification(_ identifier: String) { diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index d35de1ffe..c78342b43 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -41,7 +41,10 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension let envelope = try? MessageWrapper.unwrap(data: data), let envelopeAsData = try? envelope.serializedData() else { return self.handleFailure(for: notificationContent) } - Storage.write { transaction in // Intentionally capture self + // HACK: It is important to use writeSync() here to avoid a race condition + // where the completeSilenty() is called before the local notification request + // is added to notification center. + Storage.writeSync { transaction in // Intentionally capture self do { let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) switch message { From 83fa679574a47e8b14e806047a3f4824a4316713 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Mon, 21 Mar 2022 13:57:06 +1100 Subject: [PATCH 13/13] Fixed some incorrect logic (previously prevented joining other rooms in a server) --- SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift b/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift index 04d36c875..5e3f781be 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift @@ -56,8 +56,10 @@ public final class OpenGroupManagerV2 : NSObject { serverOptions = serverOptions.union(legacyServerOptions) } - // First check if there is an existing poller for the given server options - guard serverOptions.first(where: { OpenGroupManagerV2.shared.pollers[$0] != nil }) == nil else { return true } + // First check if there is no poller for the specified server + if serverOptions.first(where: { OpenGroupManagerV2.shared.pollers[$0] != nil }) == nil { + return false + } // Then check if there is an existing open group thread let hasExistingThread: Bool = serverOptions.contains(where: { serverName in