ios: fixed unread counters (#5640)

This commit is contained in:
Stanislav Dmitrenko
2025-02-19 03:44:24 +07:00
committed by GitHub
parent 9d1329498b
commit ec519afb3f
4 changed files with 27 additions and 66 deletions

View File

@@ -665,7 +665,7 @@ final class ChatModel: ObservableObject {
im.reversedChatItems.first?.isLiveDummy == true
}
func markChatItemsRead(_ cInfo: ChatInfo) {
func markAllChatItemsRead(_ cInfo: ChatInfo) {
// update preview
_updateChat(cInfo.id) { chat in
self.decreaseUnreadCounter(user: self.currentUser!, chat: chat)
@@ -674,54 +674,14 @@ final class ChatModel: ObservableObject {
}
// update current chat
if chatId == cInfo.id {
markCurrentChatRead()
}
}
private func markCurrentChatRead(fromIndex i: Int = 0) {
var j = i
while j < im.reversedChatItems.count {
markChatItemRead_(j)
j += 1
}
}
func markChatItemsRead(_ cInfo: ChatInfo, aboveItem: ChatItem? = nil) {
if let cItem = aboveItem {
if chatId == cInfo.id, let i = getChatItemIndex(cItem) {
markCurrentChatRead(fromIndex: i)
_updateChat(cInfo.id) { chat in
var unreadBelow = 0
var unreadMentionsBelow = 0
var j = i - 1
while j >= 0 {
let meta = self.im.reversedChatItems[j].meta
if case .rcvNew = meta.itemStatus {
unreadBelow += 1
if meta.userMention {
unreadMentionsBelow += 1
}
}
j -= 1
}
// update preview
let markedCount = chat.chatStats.unreadCount - unreadBelow
let markedMentionsCount = chat.chatStats.unreadMentions - unreadMentionsBelow
if markedCount > 0 || markedMentionsCount > 0 {
let wasUnread = chat.unreadTag
chat.chatStats.unreadCount -= markedCount
chat.chatStats.unreadMentions -= markedMentionsCount
ChatTagsModel.shared.updateChatTagRead(chat, wasUnread: wasUnread)
let by = chat.chatInfo.chatSettings?.enableNtfs == .mentions ? markedMentionsCount : markedCount
self.decreaseUnreadCounter(user: self.currentUser!, by: by)
}
}
var i = 0
while i < im.reversedChatItems.count {
markChatItemRead_(i)
i += 1
}
} else {
markChatItemsRead(cInfo)
im.chatItemsChangesListener.read(nil, im.reversedChatItems.reversed())
}
}
func markChatUnread(_ cInfo: ChatInfo, unreadChat: Bool = true) {
_updateChat(cInfo.id) { chat in
let wasUnread = chat.unreadTag
@@ -750,13 +710,16 @@ final class ChatModel: ObservableObject {
func markChatItemsRead(_ cInfo: ChatInfo, _ itemIds: [ChatItem.ID], _ mentionsRead: Int) {
if self.chatId == cInfo.id {
var unreadItemIds: Set<ChatItem.ID> = []
for itemId in itemIds {
if let i = im.reversedChatItems.firstIndex(where: { $0.id == itemId }) {
if im.reversedChatItems[i].isRcvNew {
unreadItemIds.insert(itemId)
}
var i = 0
var ids = Set(itemIds)
while i < im.reversedChatItems.count && !ids.isEmpty {
let item = im.reversedChatItems[i]
if ids.contains(item.id) && item.isRcvNew {
markChatItemRead_(i)
unreadItemIds.insert(item.id)
ids.remove(item.id)
}
i += 1
}
im.chatItemsChangesListener.read(unreadItemIds, im.reversedChatItems.reversed())
}

View File

@@ -1513,7 +1513,7 @@ func markChatRead(_ chat: Chat) async {
let cInfo = chat.chatInfo
try await apiChatRead(type: cInfo.chatType, id: cInfo.apiId)
await MainActor.run {
withAnimation { ChatModel.shared.markChatItemsRead(cInfo) }
withAnimation { ChatModel.shared.markAllChatItemsRead(cInfo) }
}
}
if chat.chatStats.unreadChat {

View File

@@ -23,11 +23,13 @@ struct MergedItems: Hashable, Equatable {
hasher.combine("\(items.hashValue)")
}
static func create(_ items: [ChatItem], _ unreadCount: Int, _ revealedItems: Set<Int64>, _ chatState: ActiveChatState) -> MergedItems {
static func create(_ items: [ChatItem], _ revealedItems: Set<Int64>, _ chatState: ActiveChatState) -> MergedItems {
if items.isEmpty {
return MergedItems(items: [], splits: [], indexInParentItems: [:])
}
let unreadCount = chatState.unreadTotal
let unreadAfterItemId = chatState.unreadAfterItemId
let itemSplits = chatState.splits
var mergedItems: [MergedItem] = []

View File

@@ -515,7 +515,7 @@ struct ChatView: View {
}
.onAppear {
Task {
mergedItems.boxedValue = MergedItems.create(im.reversedChatItems, chat.chatStats.unreadCount, revealedItems, ItemsModel.shared.chatState)
mergedItems.boxedValue = MergedItems.create(im.reversedChatItems, revealedItems, im.chatState)
let unreadIndex = mergedItems.boxedValue.items.lastIndex(where: { $0.hasUnread() })
let unreadItemId: Int64? = if let unreadIndex { mergedItems.boxedValue.items[unreadIndex].newest().item.id } else { nil }
await MainActor.run {
@@ -539,8 +539,7 @@ struct ChatView: View {
updateMergedItemsTask?.cancel()
if useItemsUpdateTask {
updateMergedItemsTask = Task {
let start = Date.now.timeIntervalSince1970
let items = MergedItems.create(items, chat.chatStats.unreadCount, revealedItems, ItemsModel.shared.chatState)
let items = MergedItems.create(items, revealedItems, im.chatState)
if Task.isCancelled {
return
}
@@ -550,18 +549,13 @@ struct ChatView: View {
}
}
} else {
mergedItems.boxedValue = MergedItems.create(items, chat.chatStats.unreadCount, revealedItems, ItemsModel.shared.chatState)
mergedItems.boxedValue = MergedItems.create(items, revealedItems, im.chatState)
scrollView.updateItems(mergedItems.boxedValue.items)
}
}
.onChange(of: revealedItems) { revealed in
updateMergedItemsTask?.cancel()
mergedItems.boxedValue = MergedItems.create(im.reversedChatItems, chat.chatStats.unreadCount, revealed, ItemsModel.shared.chatState)
scrollView.updateItems(mergedItems.boxedValue.items)
}
.onChange(of: chat.chatStats.unreadCount) { unreadCount in
updateMergedItemsTask?.cancel()
mergedItems.boxedValue = MergedItems.create(im.reversedChatItems, unreadCount, revealedItems, ItemsModel.shared.chatState)
mergedItems.boxedValue = MergedItems.create(im.reversedChatItems, revealed, im.chatState)
scrollView.updateItems(mergedItems.boxedValue.items)
}
.onChange(of: chat.id) { _ in
@@ -614,6 +608,7 @@ struct ChatView: View {
}
class FloatingButtonModel: ObservableObject {
@Published var unreadAbove: Int = 0
@Published var unreadBelow: Int = 0
@Published var isNearBottom: Bool = true
@Published var date: Date? = nil
@@ -627,6 +622,7 @@ struct ChatView: View {
} else {
0
}
let unreadAbove = ItemsModel.shared.chatState.unreadTotal - unreadBelow
let date: Date? =
if let lastVisible = listState.visibleItems.last {
Calendar.current.startOfDay(for: lastVisible.item.oldest().item.meta.itemTs)
@@ -638,6 +634,7 @@ struct ChatView: View {
DispatchQueue.main.async { [weak self] in
guard let it = self else { return }
it.setDate(visibility: true)
it.unreadAbove = unreadAbove
it.unreadBelow = unreadBelow
it.date = date
}
@@ -701,13 +698,12 @@ struct ChatView: View {
.padding(.vertical, 4)
}
VStack {
let unreadAbove = ItemsModel.shared.chatState.unreadTotal - model.unreadBelow
if unreadAbove > 0 {
if model.unreadAbove > 0 {
if loadingMoreItems {
circleButton { ProgressView() }
} else {
circleButton {
unreadCountText(unreadAbove)
unreadCountText(model.unreadAbove)
.font(.callout)
.foregroundColor(theme.colors.primary)
}