@ -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