@@ -35,7 +35,8 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
35
35
36
36
private var isActive = true
37
37
private var readsString = " "
38
- private var canMarkRead = true
38
+ private var canMarkRead = false
39
+ private var hasSetInitialCanMarkRead = false
39
40
40
41
private let messageListDateOverlay : DateFormatter = DateFormatter . messageListDateOverlay
41
42
@@ -44,7 +45,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
44
45
45
46
private var loadingPreviousMessages : Bool = false
46
47
private var loadingMessagesAround : Bool = false
47
- private var lastMessageRead : String ?
48
+ private var scrollsToUnreadAfterJumpToMessage = false
48
49
private var disableDateIndicator = false
49
50
private var channelName = " "
50
51
private var onlineIndicatorShown = false
@@ -245,25 +246,21 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
245
246
updateScrolledIdToNewestMessage ( )
246
247
} else {
247
248
channelDataSource. loadFirstPage { [ weak self] _ in
248
- self ? . scrolledId = self ? . messages. first? . messageId
249
+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.5 ) {
250
+ self ? . scrolledId = self ? . messages. first? . messageId
251
+ self ? . showScrollToLatestButton = false
252
+ }
249
253
}
250
254
}
251
255
}
252
256
253
257
public func jumpToMessage( messageId: String ) -> Bool {
254
258
if messageId == . unknownMessageId {
255
259
if firstUnreadMessageId == nil , let lastReadMessageId {
256
- channelDataSource. loadPageAroundMessageId ( lastReadMessageId) { [ weak self] error in
260
+ scrollsToUnreadAfterJumpToMessage = true
261
+ channelDataSource. loadPageAroundMessageId ( lastReadMessageId) { error in
257
262
if error != nil {
258
263
log. error ( " Error loading messages around message \( messageId) " )
259
- return
260
- }
261
- if let firstUnread = self ? . channelDataSource. firstUnreadMessageId,
262
- let message = self ? . channelController. dataStore. message ( id: firstUnread) {
263
- self ? . firstUnreadMessageId = message. messageId
264
- DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.1 ) {
265
- self ? . scrolledId = message. messageId
266
- }
267
264
}
268
265
}
269
266
}
@@ -338,13 +335,13 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
338
335
} else {
339
336
checkForNewerMessages ( index: index)
340
337
}
341
- if let firstUnreadMessageId, firstUnreadMessageId. contains ( message. id) {
338
+ if let firstUnreadMessageId, firstUnreadMessageId. contains ( message. id) , hasSetInitialCanMarkRead {
342
339
canMarkRead = true
343
340
}
344
341
if utils. messageListConfig. dateIndicatorPlacement == . overlay {
345
342
save ( lastDate: message. createdAt)
346
343
}
347
- if index == 0 {
344
+ if index == 0 , channelDataSource . hasLoadedAllNextMessages {
348
345
let isActive = UIApplication . shared. applicationState == . active
349
346
if isActive && canMarkRead {
350
347
sendReadEventIfNeeded ( for: message)
@@ -427,6 +424,17 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
427
424
428
425
refreshMessageListIfNeeded ( )
429
426
427
+ // Jump to a message but we were already scrolled to the bottom
428
+ if !channelDataSource. hasLoadedAllNextMessages {
429
+ showScrollToLatestButton = true
430
+ }
431
+
432
+ // Set scroll id after the message id has changed
433
+ if scrollsToUnreadAfterJumpToMessage, let firstUnreadMessageId {
434
+ scrollsToUnreadAfterJumpToMessage = false
435
+ scrolledId = firstUnreadMessageId
436
+ }
437
+
430
438
if !showScrollToLatestButton && scrolledId == nil && !loadingNextMessages {
431
439
updateScrolledIdToNewestMessage ( )
432
440
}
@@ -441,6 +449,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
441
449
checkTypingIndicator ( )
442
450
checkHeaderType ( )
443
451
checkOnlineIndicator ( )
452
+ checkUnreadCount ( )
444
453
}
445
454
446
455
public func showReactionOverlay( for view: AnyView ) {
@@ -472,31 +481,29 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
472
481
// MARK: - private
473
482
474
483
private func checkForOlderMessages( index: Int ) {
475
- if index < channelDataSource. messages. count - 25 {
476
- return
477
- }
478
-
484
+ guard index >= channelDataSource. messages. count - 25 else { return }
485
+ guard !loadingPreviousMessages else { return }
486
+ guard !channelController . hasLoadedAllPreviousMessages else { return }
487
+
479
488
log. debug ( " Loading previous messages " )
480
- if ! loadingPreviousMessages {
481
- loadingPreviousMessages = true
482
- channelDataSource . loadPreviousMessages (
483
- before : nil ,
484
- limit : utils . messageListConfig . pageSize ,
485
- completion : { [ weak self] _ in
486
- guard let self = self else { return }
489
+ loadingPreviousMessages = true
490
+ channelDataSource . loadPreviousMessages (
491
+ before : nil ,
492
+ limit : utils . messageListConfig . pageSize ,
493
+ completion : { [ weak self ] _ in
494
+ guard let self = self else { return }
495
+ DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.5 ) {
487
496
self . loadingPreviousMessages = false
488
497
}
489
- )
490
- }
498
+ }
499
+ )
491
500
}
492
501
493
502
private func checkForNewerMessages( index: Int ) {
494
- if channelDataSource. hasLoadedAllNextMessages {
495
- return
496
- }
497
- if loadingNextMessages || ( index > 5 ) {
498
- return
499
- }
503
+ guard index <= 5 else { return }
504
+ guard !loadingNextMessages else { return }
505
+ guard !channelController. hasLoadedAllNextMessages else { return }
506
+
500
507
loadingNextMessages = true
501
508
502
509
if scrollPosition != messages. first? . messageId {
@@ -529,13 +536,11 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
529
536
}
530
537
531
538
private func sendReadEventIfNeeded( for message: ChatMessage ) {
532
- if message. id != lastMessageRead {
533
- lastMessageRead = message. id
534
- throttler. throttle { [ weak self] in
535
- self ? . channelController. markRead ( )
536
- DispatchQueue . main. async {
537
- self ? . firstUnreadMessageId = nil
538
- }
539
+ guard let channel, channel. unreadCount. messages > 0 else { return }
540
+ throttler. throttle { [ weak self] in
541
+ self ? . channelController. markRead ( )
542
+ DispatchQueue . main. async {
543
+ self ? . firstUnreadMessageId = nil
539
544
}
540
545
}
541
546
}
@@ -633,7 +638,14 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
633
638
634
639
private func checkUnreadCount( ) {
635
640
guard !isMessageThread else { return }
636
- if channelController. channel? . unreadCount. messages ?? 0 > 0 {
641
+
642
+ guard let channel = channelController. channel else { return }
643
+ // Delay marking any messages as read until channel has loaded for the first time (slow internet + observer delay)
644
+ guard !hasSetInitialCanMarkRead else { return }
645
+ hasSetInitialCanMarkRead = true
646
+ canMarkRead = true
647
+
648
+ if channel. unreadCount. messages > 0 {
637
649
if channelController. firstUnreadMessageId != nil {
638
650
firstUnreadMessageId = channelController. firstUnreadMessageId
639
651
canMarkRead = false
@@ -657,7 +669,13 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
657
669
}
658
670
659
671
private func shouldAnimate( changes: [ ListChange < ChatMessage > ] ) -> Bool {
660
- if !utils. messageListConfig. messageDisplayOptions. animateChanges || loadingNextMessages {
672
+ if !utils. messageListConfig. messageDisplayOptions. animateChanges {
673
+ return false
674
+ }
675
+ if loadingMessagesAround || loadingPreviousMessages || loadingNextMessages {
676
+ return false
677
+ }
678
+ if channelController. channel == nil {
661
679
return false
662
680
}
663
681
0 commit comments