diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index ea8e7fe3e..b19f66fe8 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -2184,6 +2184,9 @@ typedef enum : NSUInteger { header:(JSQMessagesLoadEarlierHeaderView *)headerView didTapLoadEarlierMessagesButton:(UIButton *)sender { + OWSAssert(!self.isUserScrolling); + + BOOL hasMoreUnseenMessages = self.dynamicInteractions.hasMoreUnseenMessages; // We want to restore the current scroll state after we update the range, update // the dynamic interactions and re-layout. Here we take a "before" snapshot. @@ -2229,13 +2232,16 @@ typedef enum : NSUInteger { [self.collectionView layoutSubviews]; self.collectionView.contentOffset = CGPointMake(0, self.collectionView.contentSize.height - scrollDistanceToBottom); + [self.scrollLaterTimer invalidate]; - // We want to scroll to the bottom _after_ the layout has been updated. - self.scrollLaterTimer = [NSTimer weakScheduledTimerWithTimeInterval:0.001f - target:self - selector:@selector(scrollToUnreadIndicatorAnimated) - userInfo:nil - repeats:NO]; + if (hasMoreUnseenMessages) { + // We want to scroll to the bottom _after_ the layout has been updated. + self.scrollLaterTimer = [NSTimer weakScheduledTimerWithTimeInterval:0.001f + target:self + selector:@selector(scrollToUnreadIndicatorAnimated) + userInfo:nil + repeats:NO]; + } [self updateLoadEarlierVisible]; } diff --git a/Signal/src/util/ThreadUtil.h b/Signal/src/util/ThreadUtil.h index a79199b57..5a4bf67e8 100644 --- a/Signal/src/util/ThreadUtil.h +++ b/Signal/src/util/ThreadUtil.h @@ -36,6 +36,8 @@ NS_ASSUME_NONNULL_BEGIN // YES in ensureDynamicInteractionsForThread:... @property (nonatomic, nullable) NSNumber *firstUnseenInteractionTimestamp; +@property (nonatomic) BOOL hasMoreUnseenMessages; + - (void)clearUnreadIndicatorState; @end diff --git a/Signal/src/util/ThreadUtil.m b/Signal/src/util/ThreadUtil.m index e3ea27574..6b5ed208b 100644 --- a/Signal/src/util/ThreadUtil.m +++ b/Signal/src/util/ThreadUtil.m @@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN { self.unreadIndicatorPosition = nil; self.firstUnseenInteractionTimestamp = nil; + self.hasMoreUnseenMessages = NO; } @end @@ -200,7 +201,6 @@ NS_ASSUME_NONNULL_BEGIN // so that it can widen its "load window" to always show // the unread indicator. __block long visibleUnseenMessageCount = 0; - __block BOOL hasMoreUnseenMessages = NO; __block TSInteraction *interactionAfterUnreadIndicator = nil; NSUInteger missingUnseenSafetyNumberChangeCount = 0; if (result.firstUnseenInteractionTimestamp != nil) { @@ -243,13 +243,13 @@ NS_ASSUME_NONNULL_BEGIN // messages view, show the unread indicator at the top of the // displayed messages. *stop = YES; - hasMoreUnseenMessages = YES; + result.hasMoreUnseenMessages = YES; } }]; OWSAssert(interactionAfterUnreadIndicator); - if (hasMoreUnseenMessages) { + if (result.hasMoreUnseenMessages) { NSMutableSet *missingUnseenSafetyNumberChanges = [NSMutableSet set]; for (TSInvalidIdentityKeyErrorMessage *safetyNumberChange in blockingSafetyNumberChanges) { BOOL isUnseen = safetyNumberChange.timestampForSorting @@ -403,7 +403,7 @@ NS_ASSUME_NONNULL_BEGIN TSUnreadIndicatorInteraction *indicator = [[TSUnreadIndicatorInteraction alloc] initWithTimestamp:indicatorTimestamp thread:thread - hasMoreUnseenMessages:hasMoreUnseenMessages + hasMoreUnseenMessages:result.hasMoreUnseenMessages missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount]; [indicator saveWithTransaction:transaction];