@ -138,11 +138,13 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        result . showsVerticalScrollIndicator  =  false 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        result . contentInsetAdjustmentBehavior  =  . never 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        result . keyboardDismissMode  =  . interactive 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  bottomInset :  CGFloat  =  viewModel . threadData . canWrite  ?  Values . mediumSpacing  :  Values . mediumSpacing  +  UIApplication . shared . keyWindow ! . safeAreaInsets . bottom 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        result . contentInset  =  UIEdgeInsets ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            top :  0 , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            leading :  0 , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            bottom :  bottomInset , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            bottom :  ( viewModel . threadData . canWrite  ? 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                Values . mediumSpacing  : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                ( Values . mediumSpacing  +  ( UIApplication . shared . keyWindow ? . safeAreaInsets . bottom  ? ?  0 ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            ) , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            trailing :  0 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        result . registerHeaderFooterView ( view :  UITableViewHeaderFooterView . self ) 
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -604,11 +606,8 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            snInputView . text  =  draft 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   N o w   w e   h a v e   d o n e   a l l   t h e   n e e d e d   d i f f s ,   u p d a t e   t h e   v i e w M o d e l   w i t h   t h e   l a t e s t   d a t a   a n d   m a r k 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   a l l   m e s s a g e s   a s   r e a d   ( w e   d o   i t   i n   h e r e   a s   t h e   ' t h r e a d D a t a '   a c t u a l l y   c o n t a i n s   t h e   l a s t 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   ' i n t e r a c t i o n I d '   f o r   t h e   t h r e a d ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   N o w   w e   h a v e   d o n e   a l l   t h e   n e e d e d   d i f f s   u p d a t e   t h e   v i e w M o d e l   w i t h   t h e   l a t e s t   d a t a 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . viewModel . updateThreadData ( updatedThreadData ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . viewModel . markAllAsRead ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        // /   * * N o t e : * *   T h i s   n e e d s   t o   h a p p e n   * * a f t e r * *   w e   h a v e   u p d a t e   t h e   v i e w M o d e l ' s   t h r e a d   d a t a 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if  initialLoad  ||  viewModel . threadData . currentUserIsClosedGroupMember  !=  updatedThreadData . currentUserIsClosedGroupMember  { 
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -682,7 +681,8 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            source :  viewModel . interactionData , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            target :  updatedData 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  isInsert :  Bool  =  ( changeset . map ( {  $0 . elementInserted . count  } ) . reduce ( 0 ,  + )  >  0 ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  numItemsInserted :  Int  =  changeset . map  {  $0 . elementInserted . count  } . reduce ( 0 ,  + ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  isInsert :  Bool  =  ( numItemsInserted  >  0 ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  wasLoadingMore :  Bool  =  self . isLoadingMore 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  wasOffsetCloseToBottom :  Bool  =  self . isCloseToBottom 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  numItemsInUpdatedData :  [ Int ]  =  updatedData . map  {  $0 . elements . count  } 
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -758,10 +758,12 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            else  if  wasOffsetCloseToBottom  &&  ! wasLoadingMore  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                //   S c r o l l   t o   t h e   b o t t o m   i f   a n   i n t e r a c t i o n   w a s   j u s t   i n s e r t e d   a n d   w e   e i t h e r 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                //   j u s t   s e n t   a   m e s s a g e   o r   a r e   c l o s e   e n o u g h   t o   t h e   b o t t o m   ( w a i t   a   t i n y   f r a c t i o n 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                //   t o   a v o i d   b u g g y   a n i m a t i o n   b e h a v i o u r ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            else  if  wasOffsetCloseToBottom  &&  ! wasLoadingMore  &&  numItemsInserted  <  5  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                // /   S c r o l l   t o   t h e   b o t t o m   i f   a n   i n t e r a c t i o n   w a s   j u s t   i n s e r t e d   a n d   w e   e i t h e r   j u s t   s e n t   a   m e s s a g e   o r   a r e   c l o s e   e n o u g h   t o   t h e 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                // /   b o t t o m   ( w a i t   a   t i n y   f r a c t i o n   t o   a v o i d   b u g g y   a n i m a t i o n   b e h a v i o u r ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                // / 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                // /   * * N o t e : * *   W e   w o n ' t   a u t o m a t i c a l l y   s c r o l l   t o   t h e   b o t t o m   i f   5   o r   m o r e   m e s s a g e s   w e r e   i n s e r t e d   ( t o   a v o i d   e n d l e s s l y 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                // /   a u t o - s c r o l l i n g   t o   t h e   b o t t o m   w h e n   f e t c h i n g   n e w   p a g e s   o f   d a t a   w i t h i n   o p e n   g r o u p s 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                DispatchQueue . main . asyncAfter ( deadline :  . now ( )  +  . milliseconds ( 100 ) )  {  [ weak  self ]  in 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    self ? . scrollToBottom ( isAnimated :  true ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                } 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -771,6 +773,11 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                self . isLoadingMore  =  false 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                self . autoLoadNextPageIfNeeded ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            else  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                //   N e e d   t o   u p d a t e   t h e   s c r o l l   b u t t o n   a l p h a   i n   c a s e   n e w   m e s s a g e s   w e r e   a d d e d   b u t   w e   d i d n ' t   s c r o l l 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                self . scrollButton . alpha  =  self . getScrollButtonOpacity ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                self . unreadCountView . alpha  =  self . scrollButton . alpha 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            return 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -1311,6 +1318,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . handleInitialOffsetBounceBug ( targetIndexPath :  targetIndexPath ,  at :  . bottom ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . viewModel . markAsRead ( beforeInclusive :  nil ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    func  scrollViewWillBeginDragging ( _  scrollView :  UIScrollView )  { 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -1322,8 +1330,41 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    func  scrollViewDidScroll ( _  scrollView :  UIScrollView )  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        scrollButton . alpha  =  getScrollButtonOpacity ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        unreadCountView . alpha  =  scrollButton . alpha 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . scrollButton . alpha  =  self . getScrollButtonOpacity ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . unreadCountView . alpha  =  self . scrollButton . alpha 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   W e   w a n t   t o   m a r k   m e s s a g e s   a s   r e a d   w h i l e   w e   s c r o l l ,   s o   g r a b   t h e   n e w e s t   m e s s a g e   a n d   m a r k 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   e v e r y t h i n g   o l d e r   a s   r e a d 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        // 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   N o t e :   F o r   t h e   ' t a b l e V i s u a l B o t t o m '   w e   r e m o v e   t h e   ' V a l u e s . m e d i u m S p a c i n g '   a s   t h a t   i s   t h e   d i s t a n c e 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   t h e   t a b l e   c o n t e n t   a p p e a r s   a b o v e   t h e   i n p u t   v i e w 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        let  tableVisualBottom :  CGFloat  =  ( tableView . frame . maxY  -  ( tableView . contentInset . bottom  -  Values . mediumSpacing ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            let  visibleIndexPaths :  [ IndexPath ]  =  self . tableView . indexPathsForVisibleRows , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            let  messagesSection :  Int  =  visibleIndexPaths 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . first ( where :  {  self . viewModel . interactionData [ $0 . section ] . model  = =  . messages  } ) ? 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . section , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            let  newestCellViewModel :  MessageViewModel  =  visibleIndexPaths 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . sorted ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . filter ( {  $0 . section  = =  messagesSection  } ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . compactMap ( {  indexPath  ->  ( frame :  CGRect ,  cellViewModel :  MessageViewModel ) ?  in 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    guard  let  frame :  CGRect  =  tableView . cellForRow ( at :  indexPath ) ? . frame  else  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                        return  nil 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    return  ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                        view . convert ( frame ,  from :  tableView ) , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                        self . viewModel . interactionData [ indexPath . section ] . elements [ indexPath . row ] 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                } ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                //   E x c l u d e   m e s s a g e s   t h a t   a r e   p a r t i a l l y   o f f   t h e   b o t t o m   o f   t h e   s c r e e n 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . filter ( {  $0 . frame . maxY  <=  tableVisualBottom  } ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . last ? 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                . cellViewModel 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            self . viewModel . markAsRead ( beforeInclusive :  newestCellViewModel . id ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    func  scrollViewDidEndScrollingAnimation ( _  scrollView :  UIScrollView )  { 
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -1472,6 +1513,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   S t o r e   t h e   i n f o   i n c a s e   w e   n e e d   t o   l o a d   m o r e   d a t a   ( c a l l   w i l l   b e   r e - t r i g g e r e d ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . focusedInteractionId  =  interactionId 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . shouldHighlightNextScrollToInteraction  =  highlight 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . viewModel . markAsRead ( beforeInclusive :  interactionId ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        //   E n s u r e   t h e   t a r g e t   i n t e r a c t i o n   h a s   b e e n   l o a d e d 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        guard