@ -64,6 +64,7 @@
#import < SignalServiceKit / NSDate + OWS . h >
#import < SignalServiceKit / NSTimer + OWS . h >
#import < SignalServiceKit / OWSAddToContactsOfferMessage . h >
#import < SignalServiceKit / OWSAddToProfileWhitelistOfferMessage . h >
#import < SignalServiceKit / OWSAttachmentsProcessor . h >
#import < SignalServiceKit / OWSBlockingManager . h >
#import < SignalServiceKit / OWSDisappearingMessagesConfiguration . h >
@ -174,8 +175,8 @@ typedef enum : NSUInteger {
@ property ( nonatomic , readonly ) ConversationViewLayout * layout ;
@ property ( nonatomic , readonly ) ConversationStyle * conversationStyle ;
@ property ( nonatomic ) NSArray < ConversationViewItem * > * viewItems ;
@ property ( nonatomic ) NSMutableDictionary < NSString * , ConversationViewItem * > * viewItemCache ;
@ property ( nonatomic ) NSArray < id< ConversationViewItem > > * viewItems ;
@ property ( nonatomic ) NSMutableDictionary < NSString * , id< ConversationViewItem > > * viewItemCache ;
@ property ( nonatomic , nullable ) AVAudioRecorder * audioRecorder ;
@ property ( nonatomic , nullable ) OWSAudioPlayer * audioAttachmentPlayer ;
@ -214,7 +215,7 @@ typedef enum : NSUInteger {
@ property ( nonatomic ) BOOL hasClearedUnreadMessagesIndicator ;
@ property ( nonatomic ) BOOL showLoadMoreHeader ;
@ property ( nonatomic ) UILabel * loadMoreHeader ;
@ property ( nonatomic ) uint64_t lastVisible SortId ;
@ property ( nonatomic ) uint64_t lastVisible Timestamp ;
@ property ( nonatomic ) BOOL isUserScrolling ;
@ -705,7 +706,7 @@ typedef enum : NSUInteger {
[ self scrollToDefaultPosition ] ;
}
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
if ( !self . viewHasEverAppeared ) {
NSTimeInterval appearenceDuration = CACurrentMediaTime ( ) - self . viewControllerCreatedAt ;
@ -716,7 +717,7 @@ typedef enum : NSUInteger {
- ( NSIndexPath * _Nullable ) indexPathOfUnreadMessagesIndicator
{
NSInteger row = 0 ;
for ( ConversationViewItem * viewItem in self . viewItems ) {
for ( id< ConversationViewItem > viewItem in self . viewItems ) {
if ( viewItem . unreadIndicator ) {
return [ NSIndexPath indexPathForRow : row inSection : 0 ] ;
}
@ -1552,7 +1553,7 @@ typedef enum : NSUInteger {
OWSLogInfo ( @ "didChangePreferredContentSize ") ;
/ / Evacuate cached cell sizes .
for ( ConversationViewItem * viewItem in self . viewItems ) {
for ( id< ConversationViewItem > viewItem in self . viewItems ) {
[ viewItem clearCachedLayoutState ] ;
}
[ self resetContentAndLayout ] ;
@ -1890,11 +1891,7 @@ typedef enum : NSUInteger {
/ / DEPRECATED : we ' re no longer creating these incoming SN error ' s per message ,
/ / but there will be some legacy ones in the wild , behind which await
/ / as - of - yet - undecrypted messages
#pragma clang diagnostic push
#pragma clang diagnostic ignored "- Wdeprecated - declarations "
if ( [ errorMessage isKindOfClass : [ TSInvalidIdentityKeyReceivingErrorMessage class ] ] ) {
#pragma clang diagnostic pop
[ errorMessage acceptNewIdentityKey ] ;
}
} ] ;
@ -1936,12 +1933,12 @@ typedef enum : NSUInteger {
#pragma mark - MessageActionsDelegate
- ( void ) messageActionsShowDetailsForItem : ( ConversationViewItem * ) conversationViewItem
- ( void ) messageActionsShowDetailsForItem : ( id< ConversationViewItem > ) conversationViewItem
{
[ self showDetailViewForViewItem : conversationViewItem ] ;
}
- ( void ) messageActionsReplyToItem : ( ConversationViewItem * ) conversationViewItem
- ( void ) messageActionsReplyToItem : ( id< ConversationViewItem > ) conversationViewItem
{
[ self populateReplyForViewItem : conversationViewItem ] ;
}
@ -2009,27 +2006,32 @@ typedef enum : NSUInteger {
#pragma mark - ConversationViewCellDelegate
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressMediaViewItem : ( ConversationViewItem * ) viewItem
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressMediaViewItem : ( id< ConversationViewItem > ) viewItem
{
NSArray < MenuAction * > * messageActions = [ viewItem mediaActionsWithDelegate : self ] ;
NSArray < MenuAction * > * messageActions =
[ ConversationViewItemActions mediaActionsWithConversationViewItem : viewItem delegate : self ] ;
[ self presentMessageActions : messageActions withFocusedCell : cell ] ;
}
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressTextViewItem : ( ConversationViewItem * ) viewItem
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressTextViewItem : ( id< ConversationViewItem > ) viewItem
{
NSArray < MenuAction * > * messageActions = [ viewItem textActionsWithDelegate : self ] ;
NSArray < MenuAction * > * messageActions =
[ ConversationViewItemActions textActionsWithConversationViewItem : viewItem delegate : self ] ;
[ self presentMessageActions : messageActions withFocusedCell : cell ] ;
}
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressQuoteViewItem : ( ConversationViewItem * ) viewItem
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressQuoteViewItem : ( id< ConversationViewItem > ) viewItem
{
NSArray < MenuAction * > * messageActions = [ viewItem quotedMessageActionsWithDelegate : self ] ;
NSArray < MenuAction * > * messageActions =
[ ConversationViewItemActions quotedMessageActionsWithConversationViewItem : viewItem delegate : self ] ;
[ self presentMessageActions : messageActions withFocusedCell : cell ] ;
}
- ( void ) conversationCell : ( ConversationViewCell * ) cell didLongpressSystemMessageViewItem : ( ConversationViewItem * ) viewItem
- ( void ) conversationCell : ( ConversationViewCell * ) cell
didLongpressSystemMessageViewItem : ( id < ConversationViewItem > ) viewItem
{
NSArray < MenuAction * > * messageActions = [ viewItem infoMessageActionsWithDelegate : self ] ;
NSArray < MenuAction * > * messageActions =
[ ConversationViewItemActions infoMessageActionsWithConversationViewItem : viewItem delegate : self ] ;
[ self presentMessageActions : messageActions withFocusedCell : cell ] ;
}
@ -2144,7 +2146,7 @@ typedef enum : NSUInteger {
#pragma mark - OWSMessageBubbleViewDelegate
- ( void ) didTapImageViewItem : ( ConversationViewItem * ) viewItem
- ( void ) didTapImageViewItem : ( id< ConversationViewItem > ) viewItem
attachmentStream : ( TSAttachmentStream * ) attachmentStream
imageView : ( UIView * ) imageView
{
@ -2175,7 +2177,7 @@ typedef enum : NSUInteger {
[ vc presentDetailViewFromViewController : self mediaMessage : mediaMessage replacingView : imageView ] ;
}
- ( void ) didTapVideoViewItem : ( ConversationViewItem * ) viewItem
- ( void ) didTapVideoViewItem : ( id< ConversationViewItem > ) viewItem
attachmentStream : ( TSAttachmentStream * ) attachmentStream
imageView : ( UIImageView * ) imageView
{
@ -2204,7 +2206,7 @@ typedef enum : NSUInteger {
[ vc presentDetailViewFromViewController : self mediaMessage : mediaMessage replacingView : imageView ] ;
}
- ( void ) didTapAudioViewItem : ( ConversationViewItem * ) viewItem attachmentStream : ( TSAttachmentStream * ) attachmentStream
- ( void ) didTapAudioViewItem : ( id< ConversationViewItem > ) viewItem attachmentStream : ( TSAttachmentStream * ) attachmentStream
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( viewItem ) ;
@ -2234,7 +2236,7 @@ typedef enum : NSUInteger {
[ self . audioAttachmentPlayer playWithPlaybackAudioCategory ] ;
}
- ( void ) didTapTruncatedTextMessage : ( ConversationViewItem * ) conversationItem
- ( void ) didTapTruncatedTextMessage : ( id< ConversationViewItem > ) conversationItem
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( conversationItem ) ;
@ -2244,7 +2246,7 @@ typedef enum : NSUInteger {
[ self . navigationController pushViewController : view animated : YES ] ;
}
- ( void ) didTapContactShareViewItem : ( ConversationViewItem * ) conversationItem
- ( void ) didTapContactShareViewItem : ( id< ConversationViewItem > ) conversationItem
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( conversationItem ) ;
@ -2279,7 +2281,7 @@ typedef enum : NSUInteger {
[ self . contactShareViewHelper showAddToContactsWithContactShare : contactShare fromViewController : self ] ;
}
- ( void ) didTapFailedIncomingAttachment : ( ConversationViewItem * ) viewItem
- ( void ) didTapFailedIncomingAttachment : ( id< ConversationViewItem > ) viewItem
attachmentPointer : ( TSAttachmentPointer * ) attachmentPointer
{
OWSAssertIsOnMainThread ( ) ;
@ -2299,7 +2301,7 @@ typedef enum : NSUInteger {
[ self handleUnsentMessageTap : message ] ;
}
- ( void ) didTapConversationItem : ( ConversationViewItem * ) viewItem
- ( void ) didTapConversationItem : ( id< ConversationViewItem > ) viewItem
quotedReply : ( OWSQuotedReplyModel * ) quotedReply
failedThumbnailDownloadAttachmentPointer : ( TSAttachmentPointer * ) attachmentPointer
{
@ -2337,7 +2339,7 @@ typedef enum : NSUInteger {
} ] ;
}
- ( void ) didTapConversationItem : ( ConversationViewItem * ) viewItem quotedReply : ( OWSQuotedReplyModel * ) quotedReply
- ( void ) didTapConversationItem : ( id< ConversationViewItem > ) viewItem quotedReply : ( OWSQuotedReplyModel * ) quotedReply
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( viewItem ) ;
@ -2472,7 +2474,7 @@ typedef enum : NSUInteger {
return @ ( groupIndex ) ;
}
- ( void ) showDetailViewForViewItem : ( ConversationViewItem * ) conversationItem
- ( void ) showDetailViewForViewItem : ( id< ConversationViewItem > ) conversationItem
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( conversationItem ) ;
@ -2487,7 +2489,7 @@ typedef enum : NSUInteger {
[ self . navigationController pushViewController : view animated : YES ] ;
}
- ( void ) populateReplyForViewItem : ( ConversationViewItem * ) conversationItem
- ( void ) populateReplyForViewItem : ( id< ConversationViewItem > ) conversationItem
{
OWSLogDebug ( @ "user did tap reply ") ;
@ -2562,7 +2564,7 @@ typedef enum : NSUInteger {
NSIndexPath * _Nullable indexPathOfUnreadIndicator = [ self indexPathOfUnreadMessagesIndicator ] ;
if ( indexPathOfUnreadIndicator ) {
ConversationViewItem * oldIndicatorItem = [ self viewItemForIndex : indexPathOfUnreadIndicator . row ] ;
id< ConversationViewItem > oldIndicatorItem = [ self viewItemForIndex : indexPathOfUnreadIndicator . row ] ;
OWSAssertDebug ( oldIndicatorItem ) ;
/ / TODO ideally this would be happening within the * same * transaction that caused the unreadMessageIndicator
@ -2676,10 +2678,10 @@ typedef enum : NSUInteger {
BOOL isScrolledUp = scrollSpaceToBottom > pageHeight * 1. f ;
if ( self . viewItems . count > 0 ) {
ConversationViewItem * lastViewItem = [ self . viewItems lastObject ] ;
id< ConversationViewItem > lastViewItem = [ self . viewItems lastObject ] ;
OWSAssertDebug ( lastViewItem ) ;
if ( lastViewItem . interaction . sortId > self . lastVisibleSortId ) {
if ( lastViewItem . interaction . timestampForSorting > self . lastVisibleTimestamp ) {
shouldShowScrollDownButton = YES ;
} else if ( isScrolledUp ) {
shouldShowScrollDownButton = YES ;
@ -2778,6 +2780,7 @@ typedef enum : NSUInteger {
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( message ) ;
[ self updateLastVisibleTimestamp : message . timestampForSorting ] ;
self . lastMessageSentDate = [ NSDate new ] ;
[ self clearUnreadMessagesIndicator ] ;
self . inputToolbar . quotedReply = nil ;
@ -3291,7 +3294,7 @@ typedef enum : NSUInteger {
case YapDatabaseViewChangeUpdate : {
YapCollectionKey * collectionKey = rowChange . collectionKey ;
if ( collectionKey . key ) {
ConversationViewItem * _Nullable viewItem = self . viewItemCache [ collectionKey . key ] ;
id< ConversationViewItem > _Nullable viewItem = self . viewItemCache [ collectionKey . key ] ;
if ( viewItem ) {
[ self reloadInteractionForViewItem : viewItem ] ;
} else {
@ -3329,7 +3332,7 @@ typedef enum : NSUInteger {
/ / using the more extreme actions in the debug UI .
OWSFailDebug ( @ "hasMalformedRowChange ") ;
[ self resetMappings ] ;
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
[ self scrollToBottomAnimated : NO ] ;
return ;
}
@ -3339,7 +3342,7 @@ typedef enum : NSUInteger {
/ / These errors are rare .
OWSFailDebug ( @ "could not reload view items ; hard resetting message mappings . ") ;
[ self resetMappings ] ;
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
[ self scrollToBottomAnimated : NO ] ;
return ;
}
@ -3375,7 +3378,8 @@ typedef enum : NSUInteger {
( unsigned long ) rowChange . finalIndex ) ;
[ self . collectionView insertItemsAtIndexPaths : @ [ rowChange . newIndexPath ] ] ;
ConversationViewItem * _Nullable viewItem = [ self viewItemForIndex : ( NSInteger ) rowChange . finalIndex ] ;
id < ConversationViewItem > _Nullable viewItem =
[ self viewItemForIndex : ( NSInteger ) rowChange . finalIndex ] ;
if ( [ viewItem . interaction isKindOfClass : [ TSOutgoingMessage class ] ] ) {
TSOutgoingMessage * outgoingMessage = ( TSOutgoingMessage * ) viewItem . interaction ;
if ( !outgoingMessage . isFromLinkedDevice ) {
@ -3417,8 +3421,8 @@ typedef enum : NSUInteger {
if ( !finished ) {
OWSLogInfo ( @ "performBatchUpdates did not finish ") ;
}
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
if ( scrollToBottom && shouldAnimateUpdates ) {
[ self scrollToBottomAnimated : shouldAnimateScrollToBottom ] ;
@ -3510,7 +3514,7 @@ typedef enum : NSUInteger {
isOnlyModifyingLastMessage = NO ;
break ;
case YapDatabaseViewChangeInsert : {
ConversationViewItem * _Nullable viewItem = [ self viewItemForIndex : ( NSInteger ) rowChange . finalIndex ] ;
id< ConversationViewItem > _Nullable viewItem = [ self viewItemForIndex : ( NSInteger ) rowChange . finalIndex ] ;
if ( ( [ viewItem . interaction isKindOfClass : [ TSIncomingMessage class ] ] ||
[ viewItem . interaction isKindOfClass : [ TSOutgoingMessage class ] ] )
&& rowChange . finalIndex > = oldViewItemCount ) {
@ -3526,7 +3530,7 @@ typedef enum : NSUInteger {
if ( rowChange . changes == YapDatabaseViewChangedDependency ) {
continue ;
}
ConversationViewItem * _Nullable viewItem = [ self viewItemForIndex : ( NSInteger ) rowChange . finalIndex ] ;
id< ConversationViewItem > _Nullable viewItem = [ self viewItemForIndex : ( NSInteger ) rowChange . finalIndex ] ;
if ( ( [ viewItem . interaction isKindOfClass : [ TSIncomingMessage class ] ] ||
[ viewItem . interaction isKindOfClass : [ TSOutgoingMessage class ] ] )
&& rowChange . finalIndex > = oldViewItemCount ) {
@ -3857,7 +3861,7 @@ typedef enum : NSUInteger {
return lastVisibleIndexPath ;
}
- ( nullable ConversationViewItem * ) lastVisibleViewItem
- ( nullable id< ConversationViewItem > ) lastVisibleViewItem
{
NSIndexPath * _Nullable lastVisibleIndexPath = [ self lastVisibleIndexPath ] ;
if ( !lastVisibleIndexPath ) {
@ -3872,10 +3876,10 @@ typedef enum : NSUInteger {
- ( void ) didScrollToBottom
{
ConversationViewItem * _Nullable lastVisibleViewItem = [ self . viewItems lastObject ] ;
id< ConversationViewItem > _Nullable lastVisibleViewItem = [ self . viewItems lastObject ] ;
if ( lastVisibleViewItem ) {
uint64_t lastVisible SortId = lastVisibleViewItem . interaction . sortId ;
self . lastVisible SortId = MAX ( self . lastVisibleSortId , lastVisibleSortId ) ;
uint64_t lastVisible Timestamp = lastVisibleViewItem . interaction . timestampForSorting ;
self . lastVisible Timestamp = MAX ( self . lastVisibleTimestamp , lastVisibleTimestamp ) ;
}
self . scrollDownButton . hidden = YES ;
@ -3883,12 +3887,12 @@ typedef enum : NSUInteger {
self . hasUnreadMessages = NO ;
}
- ( void ) updateLastVisible SortId
- ( void ) updateLastVisible Timestamp
{
ConversationViewItem * _Nullable lastVisibleViewItem = [ self lastVisibleViewItem ] ;
id< ConversationViewItem > _Nullable lastVisibleViewItem = [ self lastVisibleViewItem ] ;
if ( lastVisibleViewItem ) {
uint64_t lastVisible SortId = lastVisibleViewItem . interaction . sortId ;
self . lastVisible SortId = MAX ( self . lastVisibleSortId , lastVisibleSortId ) ;
uint64_t lastVisible Timestamp = lastVisibleViewItem . interaction . timestampForSorting ;
self . lastVisible Timestamp = MAX ( self . lastVisibleTimestamp , lastVisibleTimestamp ) ;
}
[ self ensureScrollDownButton ] ;
@ -3901,6 +3905,15 @@ typedef enum : NSUInteger {
self . hasUnreadMessages = numberOfUnreadMessages > 0 ;
}
- ( void ) updateLastVisibleTimestamp : ( uint64_t ) timestamp
{
OWSAssertDebug ( timestamp > 0 ) ;
self . lastVisibleTimestamp = MAX ( self . lastVisibleTimestamp , timestamp ) ;
[ self ensureScrollDownButton ] ;
}
- ( void ) markVisibleMessagesAsRead
{
if ( self . presentedViewController ) {
@ -3916,16 +3929,15 @@ typedef enum : NSUInteger {
return ;
}
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
uint64_t lastVisible SortId = self . lastVisibleSortId ;
uint64_t lastVisible Timestamp = self . lastVisibleTimestamp ;
if ( lastVisible SortId == 0 ) {
if ( lastVisible Timestamp == 0 ) {
/ / No visible messages yet . New Thread .
return ;
}
[ OWSReadReceiptManager . sharedManager markAsReadLocallyBeforeSortId : self . lastVisibleSortId thread : self . thread ] ;
[ OWSReadReceiptManager . sharedManager markAsReadLocallyBeforeTimestamp : lastVisibleTimestamp thread : self . thread ] ;
}
- ( void ) updateGroupModelTo : ( TSGroupModel * ) newGroupModel successCompletion : ( void ( ^_Nullable ) ( void ) ) successCompletion
@ -4322,7 +4334,7 @@ typedef enum : NSUInteger {
- ( void ) scrollViewDidScroll : ( UIScrollView * ) scrollView
{
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
[ self autoLoadMoreIfNecessary ] ;
}
@ -4634,7 +4646,7 @@ typedef enum : NSUInteger {
/ / any new items inserted while we were not observing . We therefore find the
/ / first item at or after the "view horizon ". See the comments below which explain
/ / the "view horizon ".
ConversationViewItem * _Nullable lastViewItem = self . viewItems . lastObject ;
id< ConversationViewItem > _Nullable lastViewItem = self . viewItems . lastObject ;
BOOL hasAddedNewItems = ( lastViewItem && previousLastTimestamp
&& lastViewItem . interaction . timestamp > previousLastTimestamp . unsignedLongLongValue ) ;
@ -4665,7 +4677,7 @@ typedef enum : NSUInteger {
/ / We ' ll use this later to update the view to reflect any changes made while
/ / we were not observing the database . See extendRangeToIncludeUnobservedItems
/ / and the logic above .
ConversationViewItem * _Nullable lastViewItem = self . viewItems . lastObject ;
id< ConversationViewItem > _Nullable lastViewItem = self . viewItems . lastObject ;
if ( lastViewItem ) {
self . previousLastTimestamp = @ ( lastViewItem . interaction . timestamp ) ;
} else {
@ -4711,7 +4723,7 @@ typedef enum : NSUInteger {
NSUInteger mid = ( left + right ) / 2 ;
OWSAssertDebug ( left < = mid ) ;
OWSAssertDebug ( mid < right ) ;
ConversationViewItem * viewItem = self . viewItems [ mid ] ;
id< ConversationViewItem > viewItem = self . viewItems [ mid ] ;
if ( viewItem . interaction . timestamp > = viewHorizonTimestamp ) {
right = mid ;
} else {
@ -4720,7 +4732,7 @@ typedef enum : NSUInteger {
}
}
OWSAssertDebug ( left == right ) ;
ConversationViewItem * viewItem = self . viewItems [ left ] ;
id< ConversationViewItem > viewItem = self . viewItems [ left ] ;
if ( viewItem . interaction . timestamp > = viewHorizonTimestamp ) {
OWSLogInfo ( @ "firstIndexPathAtViewHorizonTimestamp : %zd / %zd", left, self.viewItems.count);
return [ NSIndexPath indexPathForRow : ( NSInteger ) left inSection : 0 ] ;
@ -4842,7 +4854,7 @@ typedef enum : NSUInteger {
{
OWSAssertIsOnMainThread ( ) ;
[ self updateLastVisible SortId ] ;
[ self updateLastVisible Timestamp ] ;
self . conversationStyle . viewWidth = self . collectionView . width ;
}
@ -4854,8 +4866,8 @@ typedef enum : NSUInteger {
/ / Returns NO on error .
- ( BOOL ) reloadViewItems
{
NSMutableArray < ConversationViewItem * > * viewItems = [ NSMutableArray new ] ;
NSMutableDictionary < NSString * , ConversationViewItem * > * viewItemCache = [ NSMutableDictionary new ] ;
NSMutableArray < id< ConversationViewItem > > * viewItems = [ NSMutableArray new ] ;
NSMutableDictionary < NSString * , id< ConversationViewItem > > * viewItemCache = [ NSMutableDictionary new ] ;
NSUInteger count = [ self . messageMappings numberOfItemsInSection : 0 ] ;
BOOL isGroupThread = self . isGroupConversation ;
@ -4884,12 +4896,12 @@ typedef enum : NSUInteger {
continue ;
}
ConversationViewItem * _Nullable viewItem = self . viewItemCache [ interaction . uniqueId ] ;
id< ConversationViewItem > _Nullable viewItem = self . viewItemCache [ interaction . uniqueId ] ;
if ( !viewItem ) {
viewItem = [ [ Conversation ViewItem alloc ] initWithInteraction : interaction
isGroupThread : isGroupThread
transaction : transaction
conversationStyle : self . conversationStyle ] ;
viewItem = [ [ Conversation Interaction ViewItem alloc ] initWithInteraction : interaction
isGroupThread : isGroupThread
transaction : transaction
conversationStyle : self . conversationStyle ] ;
}
[ viewItems addObject : viewItem ] ;
OWSAssertDebug ( !viewItemCache [ interaction . uniqueId ] ) ;
@ -4910,7 +4922,7 @@ typedef enum : NSUInteger {
uint64_t collapseCutoffTimestamp = [ NSDate ows_millisecondsSince1970ForDate : self . collapseCutoffDate ] ;
BOOL hasPlacedUnreadIndicator = NO ;
for ( ConversationViewItem * viewItem in viewItems ) {
for ( id< ConversationViewItem > viewItem in viewItems ) {
BOOL canShowDate = NO ;
switch ( viewItem . interaction . interactionType ) {
case OWSInteractionType_Unknown :
@ -4926,7 +4938,7 @@ typedef enum : NSUInteger {
break ;
}
uint64_t viewItemTimestamp = viewItem . interaction . receivedA tT imestamp;
uint64_t viewItemTimestamp = viewItem . interaction . timestampForSorting ;
OWSAssertDebug ( viewItemTimestamp > 0 ) ;
BOOL shouldShowDate = NO ;
@ -4958,15 +4970,17 @@ typedef enum : NSUInteger {
&& !( ( id < OWSReadTracking > ) viewItem . interaction ) . wasRead ) ;
if ( isItemUnread && !unreadIndicator && !hasPlacedUnreadIndicator && !self . hasClearedUnreadMessagesIndicator ) {
unreadIndicator = [ [ OWSUnreadIndicator alloc ] initWithFirstUnseenSortId : viewItem . interaction . sortId
hasMoreUnseenMessages : NO
missingUnseenSafetyNumberChangeCount : 0
unreadIndicatorPosition : 0 ] ;
unreadIndicator =
[ [ OWSUnreadIndicator alloc ] initUnreadIndicatorWithTimestamp : viewItem . interaction . timestamp
hasMoreUnseenMessages : NO
missingUnseenSafetyNumberChangeCount : 0
unreadIndicatorPosition : 0
firstUnseenInteractionTimestamp : viewItem . interaction . timestamp ] ;
}
/ / Place the unread indicator onto the first appropriate view item ,
/ / if any .
if ( unreadIndicator && viewItem . interaction . sortId > = unreadIndicator . firstUnseenSortId ) {
if ( unreadIndicator && viewItem . interaction . timestampForSorting > = unreadIndicator . timestamp ) {
viewItem . unreadIndicator = unreadIndicator ;
unreadIndicator = nil ;
hasPlacedUnreadIndicator = YES ;
@ -4984,9 +4998,9 @@ typedef enum : NSUInteger {
/ /
/ / NOTE : This logic uses the break properties which are set in the previous pass .
for ( NSUInteger i = 0 ; i < viewItems . count ; i + + ) {
ConversationViewItem * viewItem = viewItems [ i ] ;
ConversationViewItem * _Nullable previousViewItem = ( i > 0 ? viewItems [ i - 1 ] : nil ) ;
ConversationViewItem * _Nullable nextViewItem = ( i + 1 < viewItems . count ? viewItems [ i + 1 ] : nil ) ;
id< ConversationViewItem > viewItem = viewItems [ i ] ;
id< ConversationViewItem > _Nullable previousViewItem = ( i > 0 ? viewItems [ i - 1 ] : nil ) ;
id< ConversationViewItem > _Nullable nextViewItem = ( i + 1 < viewItems . count ? viewItems [ i + 1 ] : nil ) ;
BOOL shouldShowSenderAvatar = NO ;
BOOL shouldHideFooter = NO ;
BOOL isFirstInCluster = YES ;
@ -5116,8 +5130,7 @@ typedef enum : NSUInteger {
}
}
/ / Avoid animation churn by supressing footer - collapse on messages received recently .
if ( viewItem . interaction . receivedAtTimestamp > collapseCutoffTimestamp ) {
if ( viewItem . interaction . timestampForSorting > collapseCutoffTimestamp ) {
shouldHideFooter = NO ;
}
@ -5136,7 +5149,7 @@ typedef enum : NSUInteger {
/ / Whenever an interaction is modified , we need to reload it from the DB
/ / and update the corresponding view item .
- ( void ) reloadInteractionForViewItem : ( ConversationViewItem * ) viewItem
- ( void ) reloadInteractionForViewItem : ( id< ConversationViewItem > ) viewItem
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertDebug ( viewItem ) ;
@ -5157,7 +5170,7 @@ typedef enum : NSUInteger {
} ] ;
}
- ( nullable ConversationViewItem * ) viewItemForIndex : ( NSInteger ) index
- ( nullable id< ConversationViewItem > ) viewItemForIndex : ( NSInteger ) index
{
if ( index < 0 || index > = ( NSInteger ) self . viewItems . count ) {
OWSFailDebug ( @ "Invalid view item index : %lu", (unsigned long)index);
@ -5176,7 +5189,7 @@ typedef enum : NSUInteger {
- ( UICollectionViewCell * ) collectionView : ( UICollectionView * ) collectionView
cellForItemAtIndexPath : ( NSIndexPath * ) indexPath
{
ConversationViewItem * _Nullable viewItem = [ self viewItemForIndex : indexPath . row ] ;
id< ConversationViewItem > _Nullable viewItem = [ self viewItemForIndex : indexPath . row ] ;
ConversationViewCell * cell = [ viewItem dequeueCellForCollectionView : self . collectionView indexPath : indexPath ] ;
if ( !cell ) {
OWSFailDebug ( @ "Could not dequeue cell . ") ;