diff --git a/native/ios/Comm/AppDelegate.mm b/native/ios/Comm/AppDelegate.mm --- a/native/ios/Comm/AppDelegate.mm +++ b/native/ios/Comm/AppDelegate.mm @@ -56,6 +56,7 @@ NSString *const backgroundNotificationTypeKey = @"backgroundNotifType"; NSString *const setUnreadStatusKey = @"setUnreadStatus"; +NSString *const threadIDKey = @"threadID"; @interface AppDelegate () < RCTCxxBridgeDelegate, @@ -318,6 +319,37 @@ comm::MessageOperationsUtilities::storeMessageInfos(messageInfos); }); } + + TemporaryMessageStorage *temporaryRescindsStorage = + [[TemporaryMessageStorage alloc] initForRescinds]; + NSArray *rescindMessages = + [temporaryRescindsStorage readAndClearMessages]; + for (NSString *rescindMessage in rescindMessages) { + NSData *binaryRescindMessage = + [rescindMessage dataUsingEncoding:NSUTF8StringEncoding]; + + NSError *jsonError = nil; + NSDictionary *rescindPayload = + [NSJSONSerialization JSONObjectWithData:binaryRescindMessage + options:0 + error:&jsonError]; + if (jsonError) { + comm::Logger::log( + "Failed to deserialize persisted rescind payload. Details: " + + std::string([jsonError.localizedDescription UTF8String])); + continue; + } + + if (!(rescindPayload[setUnreadStatusKey] && rescindPayload[threadIDKey])) { + continue; + } + + std::string threadID = + std::string([rescindPayload[threadIDKey] UTF8String]); + comm::GlobalDBSingleton::instance.scheduleOrRun([threadID]() mutable { + comm::ThreadOperations::updateSQLiteUnreadStatus(threadID, false); + }); + } } // Copied from diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm --- a/native/ios/NotificationService/NotificationService.mm +++ b/native/ios/NotificationService/NotificationService.mm @@ -24,6 +24,9 @@ self.contentHandler = contentHandler; self.bestAttemptContent = [request.content mutableCopy]; + [self persistMessagePayload:self.bestAttemptContent.userInfo]; + // Message payload persistence is a higher priority task, so it has + // to happen prior to potential notification center clearing. if ([self isRescind:self.bestAttemptContent.userInfo]) { [self removeNotificationWithIdentifier:self.bestAttemptContent .userInfo[@"notificationId"]]; @@ -31,12 +34,6 @@ return; } - NSString *message = self.bestAttemptContent.userInfo[@"messageInfos"]; - if (message) { - TemporaryMessageStorage *temporaryStorage = - [[TemporaryMessageStorage alloc] init]; - [temporaryStorage writeMessage:message]; - } // TODO modify self.bestAttemptContent here self.contentHandler(self.bestAttemptContent); @@ -85,6 +82,39 @@ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); } +- (void)persistMessagePayload:(NSDictionary *)payload { + if (payload[@"messageInfos"]) { + TemporaryMessageStorage *temporaryStorage = + [[TemporaryMessageStorage alloc] init]; + [temporaryStorage writeMessage:payload[@"messageInfos"]]; + return; + } + + if (![self isRescind:payload]) { + return; + } + + NSError *jsonError = nil; + NSData *binarySerializedRescindPayload = + [NSJSONSerialization dataWithJSONObject:payload + options:0 + error:&jsonError]; + if (jsonError) { + comm::Logger::log( + "NSE: Failed to serialize rescind payload. Details: " + + std::string([jsonError.localizedDescription UTF8String])); + return; + } + + NSString *serializedRescindPayload = + [[NSString alloc] initWithData:binarySerializedRescindPayload + encoding:NSUTF8StringEncoding]; + + TemporaryMessageStorage *temporaryRescindsStorage = + [[TemporaryMessageStorage alloc] initForRescinds]; + [temporaryRescindsStorage writeMessage:serializedRescindPayload]; +} + - (BOOL)isRescind:(NSDictionary *)payload { return payload[backgroundNotificationTypeKey] && [payload[backgroundNotificationTypeKey] isEqualToString:@"CLEAR"];