Rename the view horizon.

This commit is contained in:
Matthew Chen 2018-02-22 11:03:53 -05:00
parent fabbe46114
commit 03670b4868

View file

@ -229,7 +229,7 @@ typedef enum : NSUInteger {
@property (nonatomic) BOOL hasUnreadMessages; @property (nonatomic) BOOL hasUnreadMessages;
@property (nonatomic) BOOL isPickingMediaAsDocument; @property (nonatomic) BOOL isPickingMediaAsDocument;
@property (nonatomic, nullable) NSNumber *previousLastTimestamp; @property (nonatomic, nullable) NSNumber *previousLastTimestamp;
@property (nonatomic, nullable) NSNumber *previousLastUnreadTimestamp; @property (nonatomic, nullable) NSNumber *viewHorizonTimestamp;
@end @end
@ -4159,9 +4159,8 @@ typedef enum : NSUInteger {
// When we resume observing database changes, we want to scroll to show the user // 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 // 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 // first item at or after the "view horizon". See the comments below which explain
// want to make any assumptions, so we select the item to center on based on // the "view horizon".
// "previous unread timestamp" rather than a specific interaction.
ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject; ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject;
BOOL hasAddedNewItems = (lastViewItem && BOOL hasAddedNewItems = (lastViewItem &&
previousLastTimestamp && previousLastTimestamp &&
@ -4169,18 +4168,22 @@ typedef enum : NSUInteger {
DDLogInfo(@"%@ hasAddedNewItems: %d", self.logTag, hasAddedNewItems); DDLogInfo(@"%@ hasAddedNewItems: %d", self.logTag, hasAddedNewItems);
if (hasAddedNewItems) { if (hasAddedNewItems) {
NSIndexPath *_Nullable indexPathToShow = [self firstIndexPathAtPreviousLastUnreadTimestamp]; NSIndexPath *_Nullable indexPathToShow = [self firstIndexPathAtViewHorizonTimestamp];
if (indexPathToShow) { if (indexPathToShow) {
[self.collectionView scrollToItemAtIndexPath:indexPathToShow [self.collectionView scrollToItemAtIndexPath:indexPathToShow
atScrollPosition:UICollectionViewScrollPositionCenteredVertically atScrollPosition:UICollectionViewScrollPositionCenteredVertically
animated:YES]; animated:YES];
} }
} }
self.previousLastUnreadTimestamp = nil; self.viewHorizonTimestamp = nil;
DDLogVerbose(@"%@ resumed observation of database modifications.", self.logTag); DDLogVerbose(@"%@ resumed observation of database modifications.", self.logTag);
} else { } else {
DDLogVerbose(@"%@ pausing observation of database modifications.", self.logTag); 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'll use this later to update the view to reflect any changes made while
// we were not observing the database. See extendRangeToIncludeUnobservedItems // we were not observing the database. See extendRangeToIncludeUnobservedItems
@ -4197,26 +4200,30 @@ typedef enum : NSUInteger {
[[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:self.thread.uniqueId]; [[TSDatabaseView unseenDatabaseViewExtension:transaction] firstObjectInGroup:self.thread.uniqueId];
}]; }];
if (firstUnseenInteraction) { 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 { } else {
self.previousLastUnreadTimestamp = nil; self.viewHorizonTimestamp = nil;
} }
DDLogVerbose(@"%@ paused observation of database modifications.", self.logTag); DDLogVerbose(@"%@ paused observation of database modifications.", self.logTag);
} }
} }
- (nullable NSIndexPath *)firstIndexPathAtPreviousLastUnreadTimestamp - (nullable NSIndexPath *)firstIndexPathAtViewHorizonTimestamp
{ {
OWSAssert(self.shouldObserveDBModifications); OWSAssert(self.shouldObserveDBModifications);
if (!self.previousLastUnreadTimestamp) { if (!self.viewHorizonTimestamp) {
return nil; return nil;
} }
if (self.viewItems.count < 1) { if (self.viewItems.count < 1) {
return nil; return nil;
} }
uint64_t previousLastUnreadTimestamp = self.previousLastUnreadTimestamp.unsignedLongLongValue; uint64_t viewHorizonTimestamp = self.viewHorizonTimestamp.unsignedLongLongValue;
// Binary search for the first view item whose timestamp >= the "previous last unread" timestamp. // 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 "left" rightward, discarding interactions before this cutoff.
// We want to move "right" leftward, discarding all-but-the-first interaction after 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. // 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(left <= mid);
OWSAssert(mid < right); OWSAssert(mid < right);
ConversationViewItem *viewItem = self.viewItems[mid]; ConversationViewItem *viewItem = self.viewItems[mid];
if (viewItem.interaction.timestamp >= previousLastUnreadTimestamp) { if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
right = mid; right = mid;
} else { } else {
// This is an optimization; it also ensures that we converge. // This is an optimization; it also ensures that we converge.
@ -4237,11 +4244,11 @@ typedef enum : NSUInteger {
} }
OWSAssert(left == right); OWSAssert(left == right);
ConversationViewItem *viewItem = self.viewItems[left]; ConversationViewItem *viewItem = self.viewItems[left];
if (viewItem.interaction.timestamp >= previousLastUnreadTimestamp) { if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
DDLogInfo(@"%@ firstIndexPathAtPreviousLastUnreadTimestamp: %zd / %zd", self.logTag, left, self.viewItems.count); DDLogInfo(@"%@ firstIndexPathAtViewHorizonTimestamp: %zd / %zd", self.logTag, left, self.viewItems.count);
return [NSIndexPath indexPathForRow:(NSInteger) left inSection:0]; return [NSIndexPath indexPathForRow:(NSInteger) left inSection:0];
} else { } else {
DDLogInfo(@"%@ firstIndexPathAtPreviousLastUnreadTimestamp: none / %zd", self.logTag, self.viewItems.count); DDLogInfo(@"%@ firstIndexPathAtViewHorizonTimestamp: none / %zd", self.logTag, self.viewItems.count);
return nil; return nil;
} }
} }