diff --git a/Session/Conversations/ConversationMessageMapping.swift b/Session/Conversations/ConversationMessageMapping.swift index f48503948..7075edc57 100644 --- a/Session/Conversations/ConversationMessageMapping.swift +++ b/Session/Conversations/ConversationMessageMapping.swift @@ -229,7 +229,7 @@ public class ConversationMessageMapping: NSObject { let indexPtr: UnsafeMutablePointer = UnsafeMutablePointer.allocate(capacity: 1) let wasFound = view.getGroup(nil, index: indexPtr, forKey: uniqueId, inCollection: TSInteraction.collection()) guard wasFound else { - owsFailDebug("Could not find interaction.") + SNLog("Could not find interaction.") return nil } let index = indexPtr.pointee diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index 03d148f9a..ae14bfe0a 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -731,9 +731,12 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat } func markAllAsRead() { - guard !thread.isMessageRequest() else { return } guard let lastSortID = viewItems.last?.interaction.sortId else { return } - OWSReadReceiptManager.shared().markAsReadLocally(beforeSortId: lastSortID, thread: thread) + OWSReadReceiptManager.shared().markAsReadLocally( + beforeSortId: lastSortID, + thread: thread, + trySendReadReceipt: !thread.isMessageRequest() + ) SSKEnvironment.shared.disappearingMessagesJob.cleanupMessagesWhichFailedToStartExpiringFromNow() } diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 3d3217e0f..fb307db18 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -6,6 +6,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv private var threads: YapDatabaseViewMappings! private var threadViewModelCache: [String:ThreadViewModel] = [:] // Thread ID to ThreadViewModel private var tableViewTopConstraint: NSLayoutConstraint! + private var unreadMessageRequestCount: UInt = 0 private var messageRequestCount: UInt { threads.numberOfItems(inGroup: TSMessageRequestGroup) @@ -196,7 +197,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv switch indexPath.section { case 0: let cell = tableView.dequeueReusableCell(withIdentifier: MessageRequestsCell.reuseIdentifier) as! MessageRequestsCell - cell.update(with: Int(messageRequestCount)) + cell.update(with: Int(unreadMessageRequestCount)) return cell default: @@ -263,6 +264,14 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv } } + // Update the number of unread message requests + unreadMessageRequestCount = OWSMessageUtils.sharedManager().unreadMessageRequestCount() + + // If there are no unread message requests then hide the message request banner + if unreadMessageRequestCount == 0 { + CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = true + } + return reload() } } @@ -286,11 +295,21 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv // If we need to unhide the message request row and then re-insert it if !messageRequestChanges.isEmpty { - if tableView.numberOfRows(inSection: 0) == 1 && Int(messageRequestCount) <= 0 { + // Update the number of unread message requests + unreadMessageRequestCount = OWSMessageUtils.sharedManager().unreadMessageRequestCount() + + // If there are no unread message requests then hide the message request banner + if unreadMessageRequestCount == 0 && tableView.numberOfRows(inSection: 0) == 1 { + CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] = true tableView.deleteRows(at: [IndexPath(row: 0, section: 0)], with: .automatic) } - else if tableView.numberOfRows(inSection: 0) == 0 && Int(messageRequestCount) > 0 && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] { - tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic) + else { + if tableView.numberOfRows(inSection: 0) == 1 && Int(messageRequestCount) <= 0 { + tableView.deleteRows(at: [IndexPath(row: 0, section: 0)], with: .automatic) + } + else if tableView.numberOfRows(inSection: 0) == 0 && Int(messageRequestCount) > 0 && !CurrentAppContext().appUserDefaults()[.hasHiddenMessageRequests] { + tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic) + } } } diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m index e80bf0bdb..a6578df0c 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.m @@ -140,16 +140,16 @@ NS_ASSUME_NONNULL_BEGIN return YES; } -- (void)markAsReadNowWithSendReadReceipt:(BOOL)sendReadReceipt +- (void)markAsReadNowWithTrySendReadReceipt:(BOOL)trySendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction; { [self markAsReadAtTimestamp:[NSDate millisecondTimestamp] - sendReadReceipt:sendReadReceipt + trySendReadReceipt:trySendReadReceipt transaction:transaction]; } - (void)markAsReadAtTimestamp:(uint64_t)readTimestamp - sendReadReceipt:(BOOL)sendReadReceipt + trySendReadReceipt:(BOOL)trySendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction; { if (_read && readTimestamp >= self.expireStartedAt) { @@ -174,7 +174,7 @@ NS_ASSUME_NONNULL_BEGIN expirationStartedAt:readTimestamp transaction:transaction]; - if (sendReadReceipt) { + if (trySendReadReceipt) { [OWSReadReceiptManager.sharedManager messageWasReadLocally:self]; } } diff --git a/SessionMessagingKit/Messages/Signal/TSInfoMessage.m b/SessionMessagingKit/Messages/Signal/TSInfoMessage.m index 5785196a6..9d303a1bf 100644 --- a/SessionMessagingKit/Messages/Signal/TSInfoMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSInfoMessage.m @@ -134,7 +134,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1; } - (void)markAsReadAtTimestamp:(uint64_t)readTimestamp - sendReadReceipt:(BOOL)sendReadReceipt + trySendReadReceipt:(BOOL)trySendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction { if (_read) { @@ -144,7 +144,7 @@ NSUInteger TSInfoMessageSchemaVersion = 1; _read = YES; [self saveWithTransaction:transaction]; - // Ignore sendReadReceipt, it doesn't apply to info messages. + // Ignore trySendReadReceipt, it doesn't apply to info messages. } @end diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index de65ce5cf..ec7d226e6 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -390,7 +390,7 @@ extension MessageReceiver { if let tsOutgoingMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) as? TSOutgoingMessage, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { // Mark previous messages as read if there is a sync message - OWSReadReceiptManager.shared().markAsReadLocally(beforeSortId: tsOutgoingMessage.sortId, thread: thread) + OWSReadReceiptManager.shared().markAsReadLocally(beforeSortId: tsOutgoingMessage.sortId, thread: thread, trySendReadReceipt: true) } // Update the contact's approval status of the current user if needed (if we are getting messages from diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h index d2c07812b..c2dfddec5 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.h @@ -45,7 +45,7 @@ extern NSString *const kIncomingMessageMarkedAsReadNotification; // This method can be called from any thread. - (void)messageWasReadLocally:(TSIncomingMessage *)message; -- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread; +- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread trySendReadReceipt:(BOOL)trySendReadReceipt; #pragma mark - Settings diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m index 13a1b39c2..4517e2be4 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadReceiptManager.m @@ -180,13 +180,13 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE #pragma mark - Mark as Read Locally -- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread +- (void)markAsReadLocallyBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread trySendReadReceipt:(BOOL)trySendReadReceipt { [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self markAsReadBeforeSortId:sortId thread:thread readTimestamp:[NSDate millisecondTimestamp] - wasLocal:YES + trySendReadReceipt:trySendReadReceipt transaction:transaction]; }]; } @@ -254,7 +254,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE - (void)markAsReadBeforeSortId:(uint64_t)sortId thread:(TSThread *)thread readTimestamp:(uint64_t)readTimestamp - wasLocal:(BOOL)wasLocal + trySendReadReceipt:(BOOL)trySendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction { NSMutableArray> *newlyReadList = [NSMutableArray new]; @@ -285,7 +285,7 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE } for (id readItem in newlyReadList) { - [readItem markAsReadAtTimestamp:readTimestamp sendReadReceipt:wasLocal transaction:transaction]; + [readItem markAsReadAtTimestamp:readTimestamp trySendReadReceipt:trySendReadReceipt transaction:transaction]; } } diff --git a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadTracking.h b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadTracking.h index d8afaaa41..b08071959 100644 --- a/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadTracking.h +++ b/SessionMessagingKit/Sending & Receiving/Read Tracking/OWSReadTracking.h @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN * Used both for *responding* to a remote read receipt and in response to the local user's activity. */ - (void)markAsReadAtTimestamp:(uint64_t)readTimestamp - sendReadReceipt:(BOOL)sendReadReceipt + trySendReadReceipt:(BOOL)trySendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction; @end diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index 91484bba7..00049a305 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -309,7 +309,7 @@ BOOL IsNoteToSelfEnabled(void) - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { for (id message in [self unseenMessagesWithTransaction:transaction]) { - [message markAsReadAtTimestamp:[NSDate ows_millisecondTimeStamp] sendReadReceipt:YES transaction:transaction]; + [message markAsReadAtTimestamp:[NSDate ows_millisecondTimeStamp] trySendReadReceipt:YES transaction:transaction]; } } diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.h b/SignalUtilitiesKit/Messaging/OWSMessageUtils.h index ef693b8dc..3069360bf 100644 --- a/SignalUtilitiesKit/Messaging/OWSMessageUtils.h +++ b/SignalUtilitiesKit/Messaging/OWSMessageUtils.h @@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)sharedManager; - (NSUInteger)unreadMessagesCount; +- (NSUInteger)unreadMessageRequestCount; - (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread; - (void)updateApplicationBadgeCount; diff --git a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m index fe8d0a4d1..b07a80bf8 100644 --- a/SignalUtilitiesKit/Messaging/OWSMessageUtils.m +++ b/SignalUtilitiesKit/Messaging/OWSMessageUtils.m @@ -112,6 +112,38 @@ NS_ASSUME_NONNULL_BEGIN return numberOfItems; } +- (NSUInteger)unreadMessageRequestCount { + __block NSUInteger count = 0; + + [LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) { + YapDatabaseViewTransaction *unreadMessages = [transaction ext:TSUnreadDatabaseViewExtensionName]; + NSArray *allGroups = [unreadMessages allGroups]; + // FIXME: Confusingly, `allGroups` includes contact threads as well + for (NSString *groupID in allGroups) { + TSThread *thread = [TSThread fetchObjectWithUniqueID:groupID transaction:transaction]; + + // Only increase the count for message requests + if (!thread.isMessageRequest) { continue; } + + [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; + } + count += 1; + *stop = YES; + }]; + } + }]; + + return count; +} + - (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread { __block NSUInteger numberOfItems;