Rename the view horizon.
This commit is contained in:
parent
fabbe46114
commit
03670b4868
|
@ -229,7 +229,7 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic) BOOL hasUnreadMessages;
|
||||
@property (nonatomic) BOOL isPickingMediaAsDocument;
|
||||
@property (nonatomic, nullable) NSNumber *previousLastTimestamp;
|
||||
@property (nonatomic, nullable) NSNumber *previousLastUnreadTimestamp;
|
||||
@property (nonatomic, nullable) NSNumber *viewHorizonTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -4156,12 +4156,11 @@ typedef enum : NSUInteger {
|
|||
CGPoint newContentOffset = CGPointMake(0, MAX(0, newContentHeight - viewTopToContentBottom));
|
||||
[self.collectionView setContentOffset:newContentOffset animated:NO];
|
||||
}
|
||||
|
||||
|
||||
// When we resume observing database changes, we want to scroll to show the user
|
||||
// any new items inserted while we were not observing. We therefore find the
|
||||
// first item which was previously unread and center it in the view. We don't
|
||||
// want to make any assumptions, so we select the item to center on based on
|
||||
// "previous unread timestamp" rather than a specific interaction.
|
||||
// first item at or after the "view horizon". See the comments below which explain
|
||||
// the "view horizon".
|
||||
ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject;
|
||||
BOOL hasAddedNewItems = (lastViewItem &&
|
||||
previousLastTimestamp &&
|
||||
|
@ -4169,18 +4168,22 @@ typedef enum : NSUInteger {
|
|||
|
||||
DDLogInfo(@"%@ hasAddedNewItems: %d", self.logTag, hasAddedNewItems);
|
||||
if (hasAddedNewItems) {
|
||||
NSIndexPath *_Nullable indexPathToShow = [self firstIndexPathAtPreviousLastUnreadTimestamp];
|
||||
NSIndexPath *_Nullable indexPathToShow = [self firstIndexPathAtViewHorizonTimestamp];
|
||||
if (indexPathToShow) {
|
||||
[self.collectionView scrollToItemAtIndexPath:indexPathToShow
|
||||
atScrollPosition:UICollectionViewScrollPositionCenteredVertically
|
||||
animated:YES];
|
||||
}
|
||||
}
|
||||
self.previousLastUnreadTimestamp = nil;
|
||||
self.viewHorizonTimestamp = nil;
|
||||
DDLogVerbose(@"%@ resumed observation of database modifications.", self.logTag);
|
||||
} else {
|
||||
DDLogVerbose(@"%@ pausing observation of database modifications.", self.logTag);
|
||||
// When stopping observation, try to record the timestamp of the last item.
|
||||
// When stopping observation, try to record the timestamp of the "view horizon".
|
||||
// The "view horizon" is where we'll want to focus the users when we resume
|
||||
// observation if any changes have happened while we weren't observing.
|
||||
// Ideally, we'll focus on those changes. But we can't skip over unread
|
||||
// interactions, so we prioritize those, if any.
|
||||
//
|
||||
// We'll use this later to update the view to reflect any changes made while
|
||||
// we were not observing the database. See extendRangeToIncludeUnobservedItems
|
||||
|
@ -4197,26 +4200,30 @@ typedef enum : NSUInteger {
|
|||
[[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:self.thread.uniqueId];
|
||||
}];
|
||||
if (firstUnseenInteraction) {
|
||||
self.previousLastUnreadTimestamp = @(firstUnseenInteraction.timestamp);
|
||||
// If there are any unread interactions, focus on the first one.
|
||||
self.viewHorizonTimestamp = @(firstUnseenInteraction.timestamp);
|
||||
} else if (lastViewItem) {
|
||||
// Otherwise, focus _just after_ the last interaction.
|
||||
self.viewHorizonTimestamp = @(lastViewItem.interaction.timestamp + 1);
|
||||
} else {
|
||||
self.previousLastUnreadTimestamp = nil;
|
||||
self.viewHorizonTimestamp = nil;
|
||||
}
|
||||
DDLogVerbose(@"%@ paused observation of database modifications.", self.logTag);
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSIndexPath *)firstIndexPathAtPreviousLastUnreadTimestamp
|
||||
- (nullable NSIndexPath *)firstIndexPathAtViewHorizonTimestamp
|
||||
{
|
||||
OWSAssert(self.shouldObserveDBModifications);
|
||||
|
||||
if (!self.previousLastUnreadTimestamp) {
|
||||
if (!self.viewHorizonTimestamp) {
|
||||
return nil;
|
||||
}
|
||||
if (self.viewItems.count < 1) {
|
||||
return nil;
|
||||
}
|
||||
uint64_t previousLastUnreadTimestamp = self.previousLastUnreadTimestamp.unsignedLongLongValue;
|
||||
// Binary search for the first view item whose timestamp >= the "previous last unread" timestamp.
|
||||
uint64_t viewHorizonTimestamp = self.viewHorizonTimestamp.unsignedLongLongValue;
|
||||
// Binary search for the first view item whose timestamp >= the "view horizon" timestamp.
|
||||
// We want to move "left" rightward, discarding interactions before this cutoff.
|
||||
// We want to move "right" leftward, discarding all-but-the-first interaction after this cutoff.
|
||||
// In the end, if we converge on an item _after_ this cutoff, it's the one we want.
|
||||
|
@ -4228,7 +4235,7 @@ typedef enum : NSUInteger {
|
|||
OWSAssert(left <= mid);
|
||||
OWSAssert(mid < right);
|
||||
ConversationViewItem *viewItem = self.viewItems[mid];
|
||||
if (viewItem.interaction.timestamp >= previousLastUnreadTimestamp) {
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
right = mid;
|
||||
} else {
|
||||
// This is an optimization; it also ensures that we converge.
|
||||
|
@ -4237,11 +4244,11 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
OWSAssert(left == right);
|
||||
ConversationViewItem *viewItem = self.viewItems[left];
|
||||
if (viewItem.interaction.timestamp >= previousLastUnreadTimestamp) {
|
||||
DDLogInfo(@"%@ firstIndexPathAtPreviousLastUnreadTimestamp: %zd / %zd", self.logTag, left, self.viewItems.count);
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
DDLogInfo(@"%@ firstIndexPathAtViewHorizonTimestamp: %zd / %zd", self.logTag, left, self.viewItems.count);
|
||||
return [NSIndexPath indexPathForRow:(NSInteger) left inSection:0];
|
||||
} else {
|
||||
DDLogInfo(@"%@ firstIndexPathAtPreviousLastUnreadTimestamp: none / %zd", self.logTag, self.viewItems.count);
|
||||
DDLogInfo(@"%@ firstIndexPathAtViewHorizonTimestamp: none / %zd", self.logTag, self.viewItems.count);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue