diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 9f995d6c4..4029c6013 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5067,7 +5067,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 285; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5136,7 +5136,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 285; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5197,7 +5197,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 285; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5267,7 +5267,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 285; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6152,7 +6152,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 285; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6220,7 +6220,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 284; + CURRENT_PROJECT_VERSION = 285; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 37b069500..edf49c303 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -55,6 +55,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat return messagesTableView.contentSize.height - tableViewUnobscuredHeight } + var isCloseToBottom: Bool { + let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y) + return margin <= ConversationVC.scrollToBottomMargin + } + lazy var mnemonic: String = { let identityManager = OWSIdentityManager.shared() let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection @@ -314,6 +319,13 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat baselineKeyboardHeight = newHeight self.messagesTableView.keyboardHeight = newHeight } + let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y) + // HACK: If the keyboard is coming up and we're very close to the bottom, scroll to the + // bottom. This "fixes" an issue where the conversation would randomly scroll up sometimes + // when bringing up the keyboard. + if newHeight > 200 && margin <= 2 { + scrollToBottom(isAnimated: false) + } scrollButtonConstraint?.constant = -(newHeight + 16) let newContentOffsetY = max(self.messagesTableView.contentOffset.y + min(lastPageTop, 0) + newHeight - self.messagesTableView.keyboardHeight, 0.0) self.messagesTableView.contentOffset.y = newContentOffsetY @@ -353,13 +365,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat if update.viewItem?.interaction is TSOutgoingMessage { shouldScrollToBottom = true } else { - let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y) - shouldScrollToBottom = margin <= ConversationVC.scrollToBottomMargin + shouldScrollToBottom = self.isCloseToBottom } case .update: self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .fade) - let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y) - shouldScrollToBottom = margin <= ConversationVC.scrollToBottomMargin + shouldScrollToBottom = self.isCloseToBottom default: preconditionFailure() } } diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index 3d303ca9d..33a3823fa 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -515,7 +515,7 @@ CGFloat kIconViewLength = 24; [weakSelf.navigationController pushViewController:vc animated:YES]; }]]; - if (self.isOpenGroup) { + if (self.isGroupThread) { // Notification Settings [section addItem:[OWSTableItem itemWithCustomCellBlock:^{ UITableViewCell *cell = [OWSTableItem newCell]; diff --git a/Session/Utilities/MentionUtilities.swift b/Session/Utilities/MentionUtilities.swift index 5c888b09d..f0f5be6c8 100644 --- a/Session/Utilities/MentionUtilities.swift +++ b/Session/Utilities/MentionUtilities.swift @@ -14,7 +14,7 @@ public final class MentionUtilities : NSObject { MentionsManager.populateUserPublicKeyCacheIfNeeded(for: threadID, in: transaction) } var string = string - let regex = try! NSRegularExpression(pattern: "@[0-9a-fA-F]*", options: []) + let regex = try! NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: []) let knownPublicKeys = MentionsManager.userPublicKeyCache[threadID] ?? [] // Should always be populated at this point var mentions: [(range: NSRange, publicKey: String)] = [] var outerMatch = regex.firstMatch(in: string, options: .withoutAnchoringBounds, range: NSRange(location: 0, length: string.utf16.count)) @@ -44,9 +44,4 @@ public final class MentionUtilities : NSObject { } return result } - - public static func isUserMentioned(in string: String) -> Bool { - let userPublicKey = getUserHexEncodedPublicKey() - return string.contains("@\(userPublicKey)") - } } diff --git a/SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements b/SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements index 758088249..71a223d61 100644 --- a/SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements +++ b/SessionNotificationServiceExtension/Meta/SessionNotificationServiceExtension.entitlements @@ -2,6 +2,8 @@ + com.apple.developer.usernotifications.filtering + aps-environment development com.apple.security.application-groups diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 38e2f6966..983fdb7ce 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -14,6 +14,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension override public func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler self.notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent + let userPublicKey = SNGeneralUtilities.getUserPublicKey() // Abort if the main app is running var isMainAppAndActive = false @@ -36,6 +37,10 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension do { let (message, proto) = try MessageReceiver.parse(envelopeAsData, openGroupMessageServerID: nil, using: transaction) let senderPublicKey = message.sender! + if (senderPublicKey == userPublicKey) { + // Ignore PNs for messages sent by the current user + return self.completeSilenty() + } var senderDisplayName = Storage.shared.getContact(with: senderPublicKey)?.displayName(for: .regular) ?? senderPublicKey let snippet: String var userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] @@ -47,6 +52,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } let thread = tsIncomingMessage.thread(with: transaction) if thread.isMuted { + // Ignore PNs if the thread is muted return self.completeSilenty() } let threadID = thread.uniqueId! @@ -56,6 +62,10 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension if let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction), let group = thread as? TSGroupThread, group.groupModel.groupType == .closedGroup { // Should always be true because we don't get PNs for open groups senderDisplayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderDisplayName, group.groupModel.groupName ?? MessageStrings.newGroupDefaultTitle) + if group.isOnlyNotifyingForMentions && !tsIncomingMessage.isUserMentioned { + // Ignore PNs if the group is set to only notify for mentions + return self.completeSilenty() + } } case let closedGroupControlMessage as ClosedGroupControlMessage: // TODO: We could consider actually handling the update here. Not sure if there's enough time though, seeing as though @@ -192,7 +202,7 @@ private extension String { func replacingMentions(for threadID: String, using transaction: YapDatabaseReadWriteTransaction) -> String { MentionsManager.populateUserPublicKeyCacheIfNeeded(for: threadID, in: transaction) var result = self - let regex = try! NSRegularExpression(pattern: "@[0-9a-fA-F]*", options: []) + let regex = try! NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: []) let knownPublicKeys = MentionsManager.userPublicKeyCache[threadID] ?? [] var mentions: [(range: NSRange, publicKey: String)] = [] var m0 = regex.firstMatch(in: result, options: .withoutAnchoringBounds, range: NSRange(location: 0, length: result.utf16.count))