From 06958babcbbd0bfe0724135ea9841d81762e9b3a Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Fri, 11 Mar 2022 11:43:21 +1100 Subject: [PATCH 1/2] fix unread mention indicator showing after the message is deleted --- Session.xcodeproj/project.pbxproj | 4 -- .../Database/OWSPrimaryStorage.m | 1 + SessionMessagingKit/Database/TSDatabaseView.h | 6 +++ SessionMessagingKit/Database/TSDatabaseView.m | 20 +++++++++ .../Read Tracking/OWSReadReceiptManager.m | 4 -- SessionMessagingKit/Threads/TSThread.h | 8 +++- SessionMessagingKit/Threads/TSThread.m | 23 +++++++---- .../Migrations/OWSDatabaseMigrationRunner.m | 1 - .../Migrations/UnreadMentionMigtation.swift | 41 ------------------- .../Messaging/ThreadViewModel.swift | 2 +- 10 files changed, 50 insertions(+), 60 deletions(-) delete mode 100644 SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index e94857f5a..d9eb55811 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -135,7 +135,6 @@ 7B1581E2271E743B00848B49 /* OWSSounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E1271E743B00848B49 /* OWSSounds.swift */; }; 7B1D74AA27BCC16E0030B423 /* NSENotificationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74A927BCC16E0030B423 /* NSENotificationPresenter.swift */; }; 7B1D74AC27BDE7510030B423 /* Promise+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */; }; - 7B1D74AE27C346220030B423 /* UnreadMentionMigtation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */; }; 7B1D74B027C365960030B423 /* Timer+MainThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1D74AF27C365960030B423 /* Timer+MainThread.swift */; }; 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */; }; 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; }; @@ -1130,7 +1129,6 @@ 7B1581E1271E743B00848B49 /* OWSSounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSSounds.swift; sourceTree = ""; }; 7B1D74A927BCC16E0030B423 /* NSENotificationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSENotificationPresenter.swift; sourceTree = ""; }; 7B1D74AB27BDE7510030B423 /* Promise+Timeout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Promise+Timeout.swift"; sourceTree = ""; }; - 7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadMentionMigtation.swift; sourceTree = ""; }; 7B1D74AF27C365960030B423 /* Timer+MainThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timer+MainThread.swift"; sourceTree = ""; }; 7B2DB2AD26F1B0FF0035B509 /* si */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = si; path = si.lproj/Localizable.strings; sourceTree = ""; }; 7B4C75CA26B37E0F0000AC89 /* UnsendRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsendRequest.swift; sourceTree = ""; }; @@ -3070,7 +3068,6 @@ isa = PBXGroup; children = ( B8B32044258C117C0020074B /* ContactsMigration.swift */, - 7B1D74AD27C346220030B423 /* UnreadMentionMigtation.swift */, FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */, C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, @@ -4615,7 +4612,6 @@ C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */, C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */, C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */, - 7B1D74AE27C346220030B423 /* UnreadMentionMigtation.swift in Sources */, B8F5F52925EC4F8A003BF8D4 /* BlockListUIUtils.m in Sources */, C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */, B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */, diff --git a/SessionMessagingKit/Database/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m index b4852c07a..338058af9 100644 --- a/SessionMessagingKit/Database/OWSPrimaryStorage.m +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m @@ -173,6 +173,7 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) withName:[TSDatabaseSecondaryIndexes registerTimeStampIndexExtensionName]]; [TSDatabaseView asyncRegisterUnseenDatabaseView:self]; + [TSDatabaseView asyncRegisterUnreadMentionDatabaseView:self]; [TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self]; [FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self]; diff --git a/SessionMessagingKit/Database/TSDatabaseView.h b/SessionMessagingKit/Database/TSDatabaseView.h index b4484abee..817347368 100644 --- a/SessionMessagingKit/Database/TSDatabaseView.h +++ b/SessionMessagingKit/Database/TSDatabaseView.h @@ -22,6 +22,7 @@ extern NSString *const TSMessageDatabaseViewExtensionName_Legacy; extern NSString *const TSUnreadDatabaseViewExtensionName; extern NSString *const TSUnseenDatabaseViewExtensionName; +extern NSString *const TSUnreadMentionDatabaseViewExtensionName; extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName; extern NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName; @@ -66,6 +67,11 @@ extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName; // Instances of OWSReadTracking for wasRead is NO. + (void)asyncRegisterUnseenDatabaseView:(OWSStorage *)storage; +// Should be used for "mention indicator". +// +// Instances of OWSReadTracking for wasRead is NO and isUserMentioned is YES. ++ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage; + + (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage; @end diff --git a/SessionMessagingKit/Database/TSDatabaseView.m b/SessionMessagingKit/Database/TSDatabaseView.m index 0b31a8631..87baf72f2 100644 --- a/SessionMessagingKit/Database/TSDatabaseView.m +++ b/SessionMessagingKit/Database/TSDatabaseView.m @@ -47,6 +47,7 @@ NSString *const TSMessageDatabaseViewExtensionName_Legacy = @"TSMessageDatabaseV NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName"; NSString *const TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName"; NSString *const TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName"; +NSString *const TSUnreadMentionDatabaseViewExtensionName = @"TSUnreadMentionDatabaseViewExtensionName"; NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName"; NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName"; NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName @@ -134,6 +135,25 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" storage:storage]; } ++ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage +{ + YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *( + YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { + if ([object isKindOfClass:[TSIncomingMessage class]]) { + TSIncomingMessage *message = (TSIncomingMessage *)object; + if (!message.wasRead && message.isUserMentioned) { + return message.uniqueThreadId; + } + } + return nil; + }]; + + [self registerMessageDatabaseViewWithName:TSUnreadMentionDatabaseViewExtensionName + viewGrouping:viewGrouping + version:@"2" + storage:storage]; +} + + (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage { YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy]; diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index e9ecae6e0..4517e2be4 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -287,10 +287,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE for (id readItem in newlyReadList) { [readItem markAsReadAtTimestamp:readTimestamp trySendReadReceipt:trySendReadReceipt transaction:transaction]; } - - // Update unread mention. - thread.hasUnreadMentionMessage = false; - [thread saveWithTransaction:transaction]; } #pragma mark - Settings diff --git a/SessionMessagingKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h index dbb38ed20..723a85dec 100644 --- a/SessionMessagingKit/Threads/TSThread.h +++ b/SessionMessagingKit/Threads/TSThread.h @@ -16,7 +16,6 @@ BOOL IsNoteToSelfEnabled(void); */ @interface TSThread : TSYapDatabaseObject -@property (nonatomic) BOOL hasUnreadMentionMessage; @property (nonatomic) BOOL isPinned; @property (nonatomic) BOOL shouldBeVisible; @property (nonatomic, readonly) NSDate *creationDate; @@ -72,6 +71,13 @@ BOOL IsNoteToSelfEnabled(void); - (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(unreadMessageCount(transaction:)); +/** + * @return If there is any message mentioning current user in this thread. + */ +- (BOOL)hasUnreadMentionMessage; + +- (BOOL)hasUnreadMentionMessageWithTransaction:(YapDatabaseReadTransaction *)transaction; + - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; /** diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index 0f9a5cc9a..98b5986c5 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -290,14 +290,27 @@ BOOL IsNoteToSelfEnabled(void) // return count; } +- (BOOL)hasUnreadMentionMessage +{ + __block BOOL hasUnreadMentionMessage; + [[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) { + hasUnreadMentionMessage = [self hasUnreadMentionMessageWithTransaction:transaction]; + }]; + return hasUnreadMentionMessage; +} + +- (BOOL)hasUnreadMentionMessageWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + YapDatabaseViewTransaction *unreadMentions = [transaction ext:TSUnreadMentionDatabaseViewExtensionName]; + return [unreadMentions numberOfItemsInGroup:self.uniqueId] > 0; +} + - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { for (id message in [self unseenMessagesWithTransaction:transaction]) { [message markAsReadAtTimestamp:[NSDate ows_millisecondTimeStamp] trySendReadReceipt:YES transaction:transaction]; } - // Update unread mention. - self.hasUnreadMentionMessage = false; [super saveWithTransaction:transaction]; } @@ -364,12 +377,6 @@ BOOL IsNoteToSelfEnabled(void) _lastInteractionDate = lastMessage.receivedAtDate; [super saveWithTransaction:transaction]; } - - // Update unread mention if there is a new incoming message. - if ([lastMessage isKindOfClass:[TSIncomingMessage class]] && ((TSIncomingMessage *)lastMessage).isUserMentioned) { - self.hasUnreadMentionMessage = true; - [super saveWithTransaction:transaction]; - } if (!self.shouldBeVisible) { self.shouldBeVisible = YES; diff --git a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m index ae9f58f11..a7d38515a 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m +++ b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m @@ -26,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray *)allMigrations { return @[ - [SNUnreadMentionMigration new], [SNMessageRequestsMigration new], [SNContactsMigration new] ]; diff --git a/SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift b/SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift deleted file mode 100644 index c23c327fb..000000000 --- a/SignalUtilitiesKit/Database/Migrations/UnreadMentionMigtation.swift +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -@objc(SNUnreadMentionMigration) -public class UnreadMentionMigration : OWSDatabaseMigration { - - @objc - class func migrationId() -> String { - return "003" // leave "002" for message request migration - } - - override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { - self.doMigrationAsync(completion: completion) - } - - private func doMigrationAsync(completion: @escaping OWSDatabaseMigrationCompletion) { - var threads: [TSThread] = [] - Storage.read { transaction in - TSThread.enumerateCollectionObjects(with: transaction) { object, _ in - guard let thread = object as? TSThread, let threadID = thread.uniqueId else { return } - let unreadMessages = transaction.ext(TSUnreadDatabaseViewExtensionName) as! YapDatabaseViewTransaction - unreadMessages.enumerateKeysAndObjects(inGroup: threadID) { collection, key, object, index, stop in - guard let unreadMessage = object as? TSIncomingMessage else { return } - if unreadMessage.wasRead { return } - if unreadMessage.isUserMentioned { - thread.hasUnreadMentionMessage = true - stop.pointee = true - } - } - threads.append(thread) - } - } - Storage.write(with: { transaction in - threads.forEach { thread in - thread.save(with: transaction) - } - self.save(with: transaction) // Intentionally capture self - }, completion: { - completion() - }) - } -} diff --git a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift index d68bf7d75..8a62c0f0d 100644 --- a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift +++ b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift @@ -52,7 +52,7 @@ public class ThreadViewModel: NSObject { self.unreadCount = thread.unreadMessageCount(transaction: transaction) self.hasUnreadMessages = unreadCount > 0 - self.hasUnreadMentions = thread.hasUnreadMentionMessage + self.hasUnreadMentions = thread.hasUnreadMentionMessage(with: transaction) } @objc From 48c74d9476a0bdd2c00a857fb29c14deb1a19926 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Fri, 11 Mar 2022 15:48:12 +1100 Subject: [PATCH 2/2] refactor to apply this logic to unread message count --- SessionMessagingKit/Threads/TSThread.h | 4 +-- SessionMessagingKit/Threads/TSThread.m | 12 ++++----- .../Messaging/OWSMessageUtils.m | 25 +++++-------------- .../Messaging/ThreadViewModel.swift | 2 +- 4 files changed, 15 insertions(+), 28 deletions(-) diff --git a/SessionMessagingKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h index 723a85dec..9a925a177 100644 --- a/SessionMessagingKit/Threads/TSThread.h +++ b/SessionMessagingKit/Threads/TSThread.h @@ -74,9 +74,9 @@ BOOL IsNoteToSelfEnabled(void); /** * @return If there is any message mentioning current user in this thread. */ -- (BOOL)hasUnreadMentionMessage; +- (NSUInteger)unreadMentionMessageCount; -- (BOOL)hasUnreadMentionMessageWithTransaction:(YapDatabaseReadTransaction *)transaction; +- (NSUInteger)unreadMentionMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction; - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index 98b5986c5..3311f5705 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -290,19 +290,19 @@ BOOL IsNoteToSelfEnabled(void) // return count; } -- (BOOL)hasUnreadMentionMessage +- (NSUInteger)unreadMentionMessageCount { - __block BOOL hasUnreadMentionMessage; + __block NSUInteger unreadMentionMessageCount; [[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) { - hasUnreadMentionMessage = [self hasUnreadMentionMessageWithTransaction:transaction]; + unreadMentionMessageCount = [self unreadMentionMessageCountWithTransaction:transaction]; }]; - return hasUnreadMentionMessage; + return unreadMentionMessageCount; } -- (BOOL)hasUnreadMentionMessageWithTransaction:(YapDatabaseReadTransaction *)transaction +- (NSUInteger)unreadMentionMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction { YapDatabaseViewTransaction *unreadMentions = [transaction ext:TSUnreadMentionDatabaseViewExtensionName]; - return [unreadMentions numberOfItemsInGroup:self.uniqueId] > 0; + return [unreadMentions numberOfItemsInGroup:self.uniqueId]; } - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m index d0facfff8..cbc703c91 100644 --- a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m +++ b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m @@ -81,25 +81,12 @@ NS_ASSUME_NONNULL_BEGIN BOOL isGroupThread = thread.isGroupThread; - [unreadMessages enumerateKeysAndObjectsInGroup:groupID - usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { - return; - } - id unread = (id)object; - if (unread.read) { - NSLog(@"Found an already read message in the * unread * messages list."); - return; - } - // We have to filter those unread messages for groups that only notifiy for mentions - if ([object isKindOfClass:TSIncomingMessage.class] && isGroupThread) { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)object; - if (((TSGroupThread *)thread).isOnlyNotifyingForMentions && !incomingMessage.isUserMentioned) { - return; - } - } - count += 1; - }]; + // For groups that only notifiy for mentions + if (isGroupThread && ((TSGroupThread *)thread).isOnlyNotifyingForMentions) { + count += [thread unreadMentionMessageCountWithTransaction:transaction]; + } else { + count += [thread unreadMessageCountWithTransaction:transaction]; + } } }]; diff --git a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift index 8a62c0f0d..12bcfd560 100644 --- a/SignalUtilitiesKit/Messaging/ThreadViewModel.swift +++ b/SignalUtilitiesKit/Messaging/ThreadViewModel.swift @@ -52,7 +52,7 @@ public class ThreadViewModel: NSObject { self.unreadCount = thread.unreadMessageCount(transaction: transaction) self.hasUnreadMessages = unreadCount > 0 - self.hasUnreadMentions = thread.hasUnreadMentionMessage(with: transaction) + self.hasUnreadMentions = thread.unreadMentionMessageCount(with: transaction) > 0 } @objc