Added a notification to indicate the user has a new message request

Fixed a bug where the notification count could be increased for message requests
Fixed a bug where an approved contact could be 'unapproved' due to an order of execution issue when generating the config sync message
Fixed a check to avoid registering for push notifications when on the simulator (old check didn't cater for M1 Macs)
Moved the 'hasHiddenMessageRequests' into the group user defaults so it can be accessed within the notification extension
Added code to handle an edge case where an old client could incorrectly un-approve a contact via a legacy configuration message
pull/559/head
Morgan Pretty 3 years ago
parent dfbee2a520
commit 47314bd639

@ -65,7 +65,6 @@
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; }; 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; }; 4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; };
4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BC20470A5B00CEE724 /* classic.aifc */; }; 4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BC20470A5B00CEE724 /* classic.aifc */; };
450DF2051E0D74AC003D14BE /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2041E0D74AC003D14BE /* Platform.swift */; };
450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */; }; 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */; };
451166C01FD86B98000739BA /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451166BF1FD86B98000739BA /* AccountManager.swift */; }; 451166C01FD86B98000739BA /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451166BF1FD86B98000739BA /* AccountManager.swift */; };
451A13B11E13DED2000A50FD /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A13B01E13DED2000A50FD /* AppNotifications.swift */; }; 451A13B11E13DED2000A50FD /* AppNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A13B01E13DED2000A50FD /* AppNotifications.swift */; };
@ -1052,7 +1051,6 @@
4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "classic-quiet.aifc"; sourceTree = "<group>"; }; 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "classic-quiet.aifc"; sourceTree = "<group>"; };
4503F1BC20470A5B00CEE724 /* classic.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = classic.aifc; sourceTree = "<group>"; }; 4503F1BC20470A5B00CEE724 /* classic.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = classic.aifc; sourceTree = "<group>"; };
4509E7991DD653700025A59F /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = ThirdParty/WebRTC/Build/WebRTC.framework; sourceTree = "<group>"; }; 4509E7991DD653700025A59F /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = ThirdParty/WebRTC/Build/WebRTC.framework; sourceTree = "<group>"; };
450DF2041E0D74AC003D14BE /* Platform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = "<group>"; };
450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UserNotificationsAdaptee.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UserNotificationsAdaptee.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
451166BF1FD86B98000739BA /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; }; 451166BF1FD86B98000739BA /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; };
451A13B01E13DED2000A50FD /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppNotifications.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 451A13B01E13DED2000A50FD /* AppNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppNotifications.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
@ -2063,7 +2061,6 @@
45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */, 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */,
4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */, 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */,
4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */, 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */,
450DF2041E0D74AC003D14BE /* Platform.swift */,
4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */, 4521C3BF1F59F3BA00B4C582 /* TextFieldHelper.swift */,
34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */, 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */,
B8544E3223D50E4900299F14 /* SNAppearance.swift */, B8544E3223D50E4900299F14 /* SNAppearance.swift */,
@ -4916,7 +4913,6 @@
34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */, 34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */,
B8D0A26925E4A2C200C1835E /* Onboarding.swift in Sources */, B8D0A26925E4A2C200C1835E /* Onboarding.swift in Sources */,
34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */, 34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */,
450DF2051E0D74AC003D14BE /* Platform.swift in Sources */,
4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */, 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */,
B82149B825D60393009C0F2A /* BlockedModal.swift in Sources */, B82149B825D60393009C0F2A /* BlockedModal.swift in Sources */,
B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */, B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */,

@ -181,7 +181,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section { switch section {
case 0: case 0:
if messageRequestCount > 0 && !UserDefaults.standard[.hasHiddenMessageRequests] { if messageRequestCount > 0 && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
return 1 return 1
} }
@ -258,8 +258,8 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
.compactMap { $0 as? YapDatabaseViewRowChange } .compactMap { $0 as? YapDatabaseViewRowChange }
.filter { $0.finalGroup == TSMessageRequestGroup && $0.type == .insert } .filter { $0.finalGroup == TSMessageRequestGroup && $0.type == .insert }
if !messageRequestInserts.isEmpty && UserDefaults.standard[.hasHiddenMessageRequests] { if !messageRequestInserts.isEmpty && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
UserDefaults.standard[.hasHiddenMessageRequests] = false CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = false
} }
} }
@ -284,8 +284,8 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
tableView.beginUpdates() tableView.beginUpdates()
// If we need to unhide the message request row and then re-insert it // If we need to unhide the message request row and then re-insert it
if !messageRequestInserts.isEmpty && UserDefaults.standard[.hasHiddenMessageRequests] { if !messageRequestInserts.isEmpty && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
UserDefaults.standard[.hasHiddenMessageRequests] = false CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = false
tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic) tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
} }
@ -436,7 +436,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
switch indexPath.section { switch indexPath.section {
case 0: case 0:
let hide = UITableViewRowAction(style: .destructive, title: NSLocalizedString("TXT_HIDE_TITLE", comment: "")) { [weak self] _, _ in let hide = UITableViewRowAction(style: .destructive, title: NSLocalizedString("TXT_HIDE_TITLE", comment: "")) { [weak self] _, _ in
UserDefaults.standard[.hasHiddenMessageRequests] = true CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = true
// Animate the row removal // Animate the row removal
self?.tableView.beginUpdates() self?.tableView.beginUpdates()

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -619,5 +619,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -610,5 +610,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -609,5 +609,6 @@
"MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?"; "MESSAGE_REQUESTS_DELETE_CONFIRMATION_ACTON" = "Are you sure you want to delete this message request?";
"MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request."; "MESSAGE_REQUESTS_INFO" = "Sending a message to this user will automatically accept their message request.";
"MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted."; "MESSAGE_REQUESTS_ACCEPTED" = "Your message request has been accepted.";
"MESSAGE_REQUESTS_NOTIFICATION" = "You have a new message request";
"TXT_HIDE_TITLE" = "Hide"; "TXT_HIDE_TITLE" = "Hide";
"TXT_DELETE_ACCEPT" = "Accept"; "TXT_DELETE_ACCEPT" = "Accept";

@ -4,6 +4,8 @@
import Foundation import Foundation
import PromiseKit import PromiseKit
import SessionMessagingKit
import SignalUtilitiesKit
/// There are two primary components in our system notification integration: /// There are two primary components in our system notification integration:
/// ///
@ -88,7 +90,7 @@ let kNotificationDelayForBackgroumdPoll: TimeInterval = 5
let kAudioNotificationsThrottleCount = 2 let kAudioNotificationsThrottleCount = 2
let kAudioNotificationsThrottleInterval: TimeInterval = 5 let kAudioNotificationsThrottleInterval: TimeInterval = 5
protocol NotificationPresenterAdaptee: class { protocol NotificationPresenterAdaptee: AnyObject {
func registerNotificationSettings() -> Promise<Void> func registerNotificationSettings() -> Promise<Void>
@ -157,11 +159,32 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
} }
public func notifyUser(for incomingMessage: TSIncomingMessage, in thread: TSThread, transaction: YapDatabaseReadTransaction) { public func notifyUser(for incomingMessage: TSIncomingMessage, in thread: TSThread, transaction: YapDatabaseReadTransaction) {
guard !thread.isMuted else { return } guard !thread.isMuted else { return }
guard thread.isGroupThread() || !thread.isMessageRequest() else { return }
guard let threadId = thread.uniqueId else { return } guard let threadId = thread.uniqueId else { return }
// If the thread is a message request and the user hasn't hidden message requests then we need
// 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] {
let dbConnection: YapDatabaseConnection = OWSPrimaryStorage.shared().newDatabaseConnection()
dbConnection.objectCacheLimit = 2
dbConnection.beginLongLivedReadTransaction() // Freeze the connection for use on the main thread (this gives us a stable data source that doesn't change until we tell it to)
let threads: YapDatabaseViewMappings = YapDatabaseViewMappings(groups: [ TSMessageRequestGroup ], view: TSThreadDatabaseViewExtensionName)
dbConnection.read { transaction in
threads.update(with: transaction) // Perform the initial update
}
let numMessageRequests = threads.numberOfItems(inGroup: TSMessageRequestGroup)
dbConnection.endLongLivedReadTransaction()
// 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] {
CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = false
}
let identifier: String = incomingMessage.notificationIdentifier ?? UUID().uuidString let identifier: String = incomingMessage.notificationIdentifier ?? UUID().uuidString
let isBackgroudPoll = identifier == threadId let isBackgroudPoll = identifier == threadId
@ -186,36 +209,44 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
let senderName = Storage.shared.getContact(with: incomingMessage.authorId, using: transaction)?.displayName(for: context) ?? incomingMessage.authorId let senderName = Storage.shared.getContact(with: incomingMessage.authorId, using: transaction)?.displayName(for: context) ?? incomingMessage.authorId
let notificationTitle: String? let notificationTitle: String?
var notificationBody: String?
let previewType = preferences.notificationPreviewType(with: transaction) let previewType = preferences.notificationPreviewType(with: transaction)
switch previewType { switch previewType {
case .noNameNoPreview: case .noNameNoPreview:
notificationTitle = "Session" notificationTitle = "Session"
case .nameNoPreview, .namePreview:
switch thread { case .nameNoPreview, .namePreview:
case is TSContactThread: switch thread {
notificationTitle = senderName case is TSContactThread:
case is TSGroupThread: notificationTitle = (thread.isMessageRequest() ? "Session" : senderName)
var groupName = thread.name()
if groupName.count < 1 { case is TSGroupThread:
groupName = MessageStrings.newGroupDefaultTitle var groupName = thread.name()
if groupName.count < 1 {
groupName = MessageStrings.newGroupDefaultTitle
}
notificationTitle = isBackgroudPoll ? groupName : String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderName, groupName)
default:
owsFailDebug("unexpected thread: \(thread)")
return
} }
notificationTitle = isBackgroudPoll ? groupName : String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderName, groupName)
default: default:
owsFailDebug("unexpected thread: \(thread)") notificationTitle = "Session"
return
}
default:
notificationTitle = "Session"
} }
var notificationBody: String?
switch previewType { switch previewType {
case .noNameNoPreview, .nameNoPreview: case .noNameNoPreview, .nameNoPreview: notificationBody = NotificationStrings.incomingMessageBody
notificationBody = NotificationStrings.incomingMessageBody case .namePreview: notificationBody = messageText
case .namePreview: default: notificationBody = NotificationStrings.incomingMessageBody
notificationBody = messageText }
default:
notificationBody = NotificationStrings.incomingMessageBody // 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() {
notificationBody = NSLocalizedString("MESSAGE_REQUESTS_NOTIFICATION", comment: "")
} }
assert((notificationBody ?? notificationTitle) != nil) assert((notificationBody ?? notificationTitle) != nil)
@ -231,12 +262,15 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
DispatchQueue.main.async { DispatchQueue.main.async {
notificationBody = MentionUtilities.highlightMentions(in: notificationBody!, threadID: thread.uniqueId!) notificationBody = MentionUtilities.highlightMentions(in: notificationBody!, threadID: thread.uniqueId!)
let sound = self.requestSound(thread: thread) let sound = self.requestSound(thread: thread)
self.adaptee.notify(category: category,
title: notificationTitle, self.adaptee.notify(
body: notificationBody ?? "", category: category,
userInfo: userInfo, title: notificationTitle,
sound: sound, body: notificationBody ?? "",
replacingIdentifier: identifier) userInfo: userInfo,
sound: sound,
replacingIdentifier: identifier
)
} }
} }

@ -53,9 +53,9 @@ public enum PushRegistrationError: Error {
return firstly { return firstly {
self.registerUserNotificationSettings() self.registerUserNotificationSettings()
}.then { () -> Promise<(pushToken: String, voipToken: String)> in }.then { () -> Promise<(pushToken: String, voipToken: String)> in
guard !Platform.isSimulator else { #if targetEnvironment(simulator)
throw PushRegistrationError.pushNotSupported(description: "Push not supported on simulators") throw PushRegistrationError.pushNotSupported(description: "Push not supported on simulators")
} #endif
return self.registerForVanillaPushToken().map { vanillaPushToken -> (pushToken: String, voipToken: String) in return self.registerForVanillaPushToken().map { vanillaPushToken -> (pushToken: String, voipToken: String) in
return (pushToken: vanillaPushToken, voipToken: "") return (pushToken: vanillaPushToken, voipToken: "")

@ -1,14 +0,0 @@
// Created by Michael Kirk on 12/23/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
import Foundation
struct Platform {
static let isSimulator: Bool = {
var isSim = false
#if arch(i386) || arch(x86_64)
isSim = true
#endif
return isSim
}()
}

@ -65,6 +65,8 @@ extension ConfigurationMessage {
return return
} }
// Can just default the 'hasX' values to true as they will be set to this
// when converting to proto anyway
let profilePictureURL = contact.profilePictureURL let profilePictureURL = contact.profilePictureURL
let profileKey = contact.profileEncryptionKey?.keyData let profileKey = contact.profileEncryptionKey?.keyData
let contact = ConfigurationMessage.Contact( let contact = ConfigurationMessage.Contact(
@ -72,8 +74,11 @@ extension ConfigurationMessage {
displayName: (contact.name ?? publicKey), displayName: (contact.name ?? publicKey),
profilePictureURL: profilePictureURL, profilePictureURL: profilePictureURL,
profileKey: profileKey, profileKey: profileKey,
hasIsApproved: true,
isApproved: contact.isApproved, isApproved: contact.isApproved,
hasIsBlocked: true,
isBlocked: contact.isBlocked, isBlocked: contact.isBlocked,
hasDidApproveMe: true,
didApproveMe: contact.didApproveMe didApproveMe: contact.didApproveMe
) )

@ -194,19 +194,36 @@ extension ConfigurationMessage {
public var profilePictureURL: String? public var profilePictureURL: String?
public var profileKey: Data? public var profileKey: Data?
public var hasIsApproved: Bool
public var isApproved: Bool public var isApproved: Bool
public var hasIsBlocked: Bool
public var isBlocked: Bool public var isBlocked: Bool
public var hasDidApproveMe: Bool
public var didApproveMe: Bool public var didApproveMe: Bool
public var isValid: Bool { publicKey != nil && displayName != nil } public var isValid: Bool { publicKey != nil && displayName != nil }
public init(publicKey: String, displayName: String, profilePictureURL: String?, profileKey: Data?, isApproved: Bool, isBlocked: Bool, didApproveMe: Bool) { public init(
publicKey: String,
displayName: String,
profilePictureURL: String?,
profileKey: Data?,
hasIsApproved: Bool,
isApproved: Bool,
hasIsBlocked: Bool,
isBlocked: Bool,
hasDidApproveMe: Bool,
didApproveMe: Bool
) {
self.publicKey = publicKey self.publicKey = publicKey
self.displayName = displayName self.displayName = displayName
self.profilePictureURL = profilePictureURL self.profilePictureURL = profilePictureURL
self.profileKey = profileKey self.profileKey = profileKey
self.hasIsApproved = hasIsApproved
self.isApproved = isApproved self.isApproved = isApproved
self.hasIsBlocked = hasIsBlocked
self.isBlocked = isBlocked self.isBlocked = isBlocked
self.hasDidApproveMe = hasDidApproveMe
self.didApproveMe = didApproveMe self.didApproveMe = didApproveMe
} }
@ -217,8 +234,11 @@ extension ConfigurationMessage {
self.displayName = displayName self.displayName = displayName
self.profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String? self.profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String?
self.profileKey = coder.decodeObject(forKey: "profileKey") as! Data? self.profileKey = coder.decodeObject(forKey: "profileKey") as! Data?
self.hasIsApproved = (coder.decodeObject(forKey: "hasIsApproved") as? Bool ?? false)
self.isApproved = (coder.decodeObject(forKey: "isApproved") as? Bool ?? false) self.isApproved = (coder.decodeObject(forKey: "isApproved") as? Bool ?? false)
self.hasIsBlocked = (coder.decodeObject(forKey: "hasIsBlocked") as? Bool ?? false)
self.isBlocked = (coder.decodeObject(forKey: "isBlocked") as? Bool ?? false) self.isBlocked = (coder.decodeObject(forKey: "isBlocked") as? Bool ?? false)
self.hasDidApproveMe = (coder.decodeObject(forKey: "hasDidApproveMe") as? Bool ?? false)
self.didApproveMe = (coder.decodeObject(forKey: "didApproveMe") as? Bool ?? false) self.didApproveMe = (coder.decodeObject(forKey: "didApproveMe") as? Bool ?? false)
} }
@ -227,8 +247,11 @@ extension ConfigurationMessage {
coder.encode(displayName, forKey: "displayName") coder.encode(displayName, forKey: "displayName")
coder.encode(profilePictureURL, forKey: "profilePictureURL") coder.encode(profilePictureURL, forKey: "profilePictureURL")
coder.encode(profileKey, forKey: "profileKey") coder.encode(profileKey, forKey: "profileKey")
coder.encode(hasIsApproved, forKey: "hasIsApproved")
coder.encode(isApproved, forKey: "isApproved") coder.encode(isApproved, forKey: "isApproved")
coder.encode(hasIsBlocked, forKey: "hasIsBlocked")
coder.encode(isBlocked, forKey: "isBlocked") coder.encode(isBlocked, forKey: "isBlocked")
coder.encode(hasDidApproveMe, forKey: "hasDidApproveMe")
coder.encode(didApproveMe, forKey: "didApproveMe") coder.encode(didApproveMe, forKey: "didApproveMe")
} }
@ -238,8 +261,11 @@ extension ConfigurationMessage {
displayName: proto.name, displayName: proto.name,
profilePictureURL: proto.profilePicture, profilePictureURL: proto.profilePicture,
profileKey: proto.profileKey, profileKey: proto.profileKey,
hasIsApproved: proto.hasIsApproved,
isApproved: proto.isApproved, isApproved: proto.isApproved,
hasIsBlocked: proto.hasIsBlocked,
isBlocked: proto.isBlocked, isBlocked: proto.isBlocked,
hasDidApproveMe: proto.hasDidApproveMe,
didApproveMe: proto.didApproveMe didApproveMe: proto.didApproveMe
) )
@ -254,9 +280,9 @@ extension ConfigurationMessage {
if let profilePictureURL = profilePictureURL { result.setProfilePicture(profilePictureURL) } if let profilePictureURL = profilePictureURL { result.setProfilePicture(profilePictureURL) }
if let profileKey = profileKey { result.setProfileKey(profileKey) } if let profileKey = profileKey { result.setProfileKey(profileKey) }
result.setIsApproved(isApproved) if hasIsApproved { result.setIsApproved(isApproved) }
result.setIsBlocked(isBlocked) if hasIsBlocked { result.setIsBlocked(isBlocked) }
result.setDidApproveMe(didApproveMe) if hasDidApproveMe { result.setDidApproveMe(didApproveMe) }
do { do {
return try result.build() return try result.build()

@ -214,9 +214,14 @@ extension MessageReceiver {
if let profileKey = contactInfo.profileKey { contact.profileEncryptionKey = OWSAES256Key(data: profileKey) } if let profileKey = contactInfo.profileKey { contact.profileEncryptionKey = OWSAES256Key(data: profileKey) }
contact.profilePictureURL = contactInfo.profilePictureURL contact.profilePictureURL = contactInfo.profilePictureURL
contact.name = contactInfo.displayName contact.name = contactInfo.displayName
contact.isApproved = contactInfo.isApproved
contact.isBlocked = contactInfo.isBlocked // Note: We only update these values if the proto actually has values for them (this is to
contact.didApproveMe = contactInfo.didApproveMe // prevent an edge case where an old client could override the values with default values
// since they aren't included)
if contactInfo.hasIsApproved { contact.isApproved = contactInfo.isApproved }
if contactInfo.hasIsBlocked { contact.isBlocked = contactInfo.isBlocked }
if contactInfo.hasDidApproveMe { contact.didApproveMe = contactInfo.didApproveMe }
Storage.shared.setContact(contact, using: transaction) Storage.shared.setContact(contact, using: transaction)
let thread = TSContactThread.getOrCreateThread(withContactSessionID: sessionID, transaction: transaction) let thread = TSContactThread.getOrCreateThread(withContactSessionID: sessionID, transaction: transaction)
thread.shouldBeVisible = true thread.shouldBeVisible = true
@ -800,12 +805,18 @@ extension MessageReceiver {
// Force a config sync to ensure all devices know the contact approval state if desired (Note: This logic // Force a config sync to ensure all devices know the contact approval state if desired (Note: This logic
// should match the behaviour in AppDelegate.forceSyncConfigurationNowIfNeeded()) // should match the behaviour in AppDelegate.forceSyncConfigurationNowIfNeeded())
guard forceConfigSync else { return } guard forceConfigSync else { return }
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent() else {
return
}
let destination: Message.Destination = Message.Destination.contact(publicKey: userPublicKey) // Note: We MUST run this async as we need to ensure the database `transaction` has finished before we generate
MessageSender.send(configurationMessage, to: destination, using: transaction).retainUntilComplete() // a new configuration message (otherwise the `contact` will be loaded direct from the database and the
// `didApproveMe` value won't have been updated)
DispatchQueue.global(qos: .background).async {
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent() else {
return
}
let destination: Message.Destination = Message.Destination.contact(publicKey: userPublicKey)
MessageSender.send(configurationMessage, to: destination, using: transaction).retainUntilComplete()
}
} }
public static func handleMessageRequestResponse(_ message: MessageRequestResponse, using transaction: Any) { public static func handleMessageRequestResponse(_ message: MessageRequestResponse, using transaction: Any) {

@ -39,57 +39,91 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
let senderPublicKey = message.sender! let senderPublicKey = message.sender!
var senderDisplayName = Storage.shared.getContact(with: senderPublicKey)?.displayName(for: .regular) ?? senderPublicKey var senderDisplayName = Storage.shared.getContact(with: senderPublicKey)?.displayName(for: .regular) ?? senderPublicKey
let snippet: String let snippet: String
var userInfo: [String:Any] = [ NotificationServiceExtension.isFromRemoteKey : true ] var userInfo: [String: Any] = [ NotificationServiceExtension.isFromRemoteKey: true ]
var isMessageRequest: Bool = false
switch message { switch message {
case let visibleMessage as VisibleMessage: case let visibleMessage as VisibleMessage:
let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, isBackgroundPoll: false, using: transaction) let tsIncomingMessageID = try MessageReceiver.handleVisibleMessage(visibleMessage, associatedWithProto: proto, openGroupID: nil, isBackgroundPoll: false, using: transaction)
guard let tsMessage = TSMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else {
return self.completeSilenty() guard let tsMessage = TSMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else {
}
let thread = tsMessage.thread(with: transaction)
let threadID = thread.uniqueId!
userInfo[NotificationServiceExtension.threadIdKey] = threadID
snippet = tsMessage.previewText(with: transaction).filterForDisplay?.replacingMentions(for: threadID, using: transaction)
?? "You've got a new message"
if let tsIncomingMessage = tsMessage as? TSIncomingMessage {
if thread.isMuted || !thread.isMessageRequest() {
// Ignore PNs if the thread is muted or the thread is a message request
return self.completeSilenty() return self.completeSilenty()
} }
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 let thread = tsMessage.thread(with: transaction)
senderDisplayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderDisplayName, group.groupModel.groupName ?? MessageStrings.newGroupDefaultTitle) let threadID = thread.uniqueId!
if group.isOnlyNotifyingForMentions && !tsIncomingMessage.isUserMentioned { userInfo[NotificationServiceExtension.threadIdKey] = threadID
// Ignore PNs if the group is set to only notify for mentions snippet = tsMessage.previewText(with: transaction).filterForDisplay?.replacingMentions(for: threadID, using: transaction)
return self.completeSilenty() ?? "You've got a new message"
if let tsIncomingMessage = tsMessage as? TSIncomingMessage {
// Ignore PNs if the thread is muted
if thread.isMuted { return self.completeSilenty() }
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()
}
}
// If the thread is a message request and the user hasn't hidden message requests then we need
// 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] {
let dbConnection: YapDatabaseConnection = OWSPrimaryStorage.shared().newDatabaseConnection()
dbConnection.objectCacheLimit = 2
dbConnection.beginLongLivedReadTransaction() // Freeze the connection for use on the main thread (this gives us a stable data source that doesn't change until we tell it to)
let threads: YapDatabaseViewMappings = YapDatabaseViewMappings(groups: [ TSMessageRequestGroup ], view: TSThreadDatabaseViewExtensionName)
dbConnection.read { transaction in
threads.update(with: transaction) // Perform the initial update
}
let numMessageRequests = threads.numberOfItems(inGroup: TSMessageRequestGroup)
dbConnection.endLongLivedReadTransaction()
// Allow this to show a notification if there are no message requests (ie. this is the first one)
guard numMessageRequests == 0 else { return self.completeSilenty() }
}
else if thread.isMessageRequest() && CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] {
CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = false
}
isMessageRequest = thread.isMessageRequest()
// Store the notification ID for unsend requests to later cancel this notification
tsIncomingMessage.setNotificationIdentifier(request.identifier, transaction: transaction)
}
else {
let semaphore = DispatchSemaphore(value: 0)
let center = UNUserNotificationCenter.current()
center.getDeliveredNotifications { notifications in
let matchingNotifications = notifications.filter({ $0.request.content.userInfo[NotificationServiceExtension.threadIdKey] as? String == threadID})
center.removeDeliveredNotifications(withIdentifiers: matchingNotifications.map({ $0.request.identifier }))
// Hack: removeDeliveredNotifications seems to be async,need to wait for some time before the delivered notifications can be removed.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { semaphore.signal() }
} }
semaphore.wait()
} }
// Store the notification ID for unsend requests to later cancel this notification notificationContent.sound = OWSSounds.notificationSound(for: thread).notificationSound(isQuiet: false)
tsIncomingMessage.setNotificationIdentifier(request.identifier, transaction: transaction)
} else { case let unsendRequest as UnsendRequest:
let semaphore = DispatchSemaphore(value: 0) MessageReceiver.handleUnsendRequest(unsendRequest, using: transaction)
let center = UNUserNotificationCenter.current() return self.completeSilenty()
center.getDeliveredNotifications { notifications in
let matchingNotifications = notifications.filter({ $0.request.content.userInfo[NotificationServiceExtension.threadIdKey] as? String == threadID}) case let closedGroupControlMessage as ClosedGroupControlMessage:
center.removeDeliveredNotifications(withIdentifiers: matchingNotifications.map({ $0.request.identifier })) // TODO: We could consider actually handling the update here. Not sure if there's enough time though, seeing as though
// Hack: removeDeliveredNotifications seems to be async,need to wait for some time before the delivered notifications can be removed. // in some cases we need to send messages (e.g. our sender key) to a number of other users.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { semaphore.signal() } switch closedGroupControlMessage.kind {
case .new(_, let name, _, _, _, _): snippet = "\(senderDisplayName) added you to \(name)"
default: return self.completeSilenty()
} }
semaphore.wait()
}
notificationContent.sound = OWSSounds.notificationSound(for: thread).notificationSound(isQuiet: false)
case let unsendRequest as UnsendRequest:
MessageReceiver.handleUnsendRequest(unsendRequest, using: transaction)
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
// in some cases we need to send messages (e.g. our sender key) to a number of other users.
switch closedGroupControlMessage.kind {
case .new(_, let name, _, _, _, _): snippet = "\(senderDisplayName) added you to \(name)"
default: return self.completeSilenty() default: return self.completeSilenty()
}
default: return self.completeSilenty()
} }
if (senderPublicKey == userPublicKey) { if (senderPublicKey == userPublicKey) {
// Ignore PNs for messages sent by the current user // Ignore PNs for messages sent by the current user
// after handling the message. Otherwise the closed // after handling the message. Otherwise the closed
@ -98,21 +132,35 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
} }
notificationContent.userInfo = userInfo notificationContent.userInfo = userInfo
notificationContent.badge = 1 notificationContent.badge = 1
let notificationsPreference = Environment.shared.preferences!.notificationPreviewType() let notificationsPreference = Environment.shared.preferences!.notificationPreviewType()
switch notificationsPreference { switch notificationsPreference {
case .namePreview: case .namePreview:
notificationContent.title = senderDisplayName notificationContent.title = senderDisplayName
notificationContent.body = snippet notificationContent.body = snippet
case .nameNoPreview:
notificationContent.title = senderDisplayName case .nameNoPreview:
notificationContent.body = NotificationStrings.incomingMessageBody notificationContent.title = senderDisplayName
case .noNameNoPreview: notificationContent.body = NotificationStrings.incomingMessageBody
case .noNameNoPreview:
notificationContent.title = "Session"
notificationContent.body = NotificationStrings.incomingMessageBody
default: break
}
// 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 isMessageRequest {
notificationContent.title = "Session" notificationContent.title = "Session"
notificationContent.body = NotificationStrings.incomingMessageBody notificationContent.body = NSLocalizedString("MESSAGE_REQUESTS_NOTIFICATION", comment: "")
default: break
} }
self.handleSuccess(for: notificationContent) self.handleSuccess(for: notificationContent)
} catch { }
catch {
if let error = error as? MessageReceiver.Error, error.isRetryable { if let error = error as? MessageReceiver.Error, error.isRetryable {
self.handleFailure(for: notificationContent) self.handleFailure(for: notificationContent)
} }

@ -76,7 +76,8 @@ NS_ASSUME_NONNULL_BEGIN
for (NSString *groupID in allGroups) { for (NSString *groupID in allGroups) {
TSThread *thread = [TSThread fetchObjectWithUniqueID:groupID transaction:transaction]; TSThread *thread = [TSThread fetchObjectWithUniqueID:groupID transaction:transaction];
if (thread.isMuted || !thread.isMessageRequest) { continue; } // Don't increase the count for muted threads or message requests
if (thread.isMuted || thread.isMessageRequest) { continue; }
BOOL isGroupThread = thread.isGroupThread; BOOL isGroupThread = thread.isGroupThread;

Loading…
Cancel
Save