This commit is contained in:
Avently
2025-01-20 08:05:16 -08:00
parent 0150254ef7
commit 92eda6fae6
3 changed files with 64 additions and 16 deletions
@@ -21,6 +21,7 @@ struct MergedItems {
return MergedItems(items: [], splits: [], indexInParentItems: [:], snapshot: NSDiffableDataSourceSnapshot())
}
logger.debug("LALAL STEP 0")
let unreadAfterItemId = chatState.unreadAfterItemId
let itemSplits = chatState.splits
var mergedItems: [MergedItem] = []
@@ -108,6 +109,7 @@ struct MergedItems {
indexInParentItems[item.id] = visibleItemIndexInParent
index += 1
}
logger.debug("LALAL STEP 7")
var snapshot = NSDiffableDataSourceSnapshot<ReverseListSection, MergedItem>()
snapshot.appendSections([ReverseListSection.main])
snapshot.appendItems(mergedItems)
@@ -238,8 +240,22 @@ struct ListItem: Hashable {
// how many unread items before (older than) this one (excluding this one)
let unreadBefore: Int
private func chatDirHash(_ chatDir: CIDirection?) -> Int {
guard let chatDir else { return 0 }
return switch chatDir {
case .directSnd: 0
case .directRcv: 1
case .groupSnd: 2
case let .groupRcv(mem): "\(mem.groupMemberId) \(mem.displayName) \(mem.memberStatus.rawValue) \(mem.memberRole.rawValue) \(mem.image?.hash ?? 0)".hash
case .localSnd: 4
case .localRcv: 5
}
}
// using meta.hashValue instead of parts of it gives 120ms vs 90ms for MergedItems list generation for 1800 items (+ snapshot time generation for UITableView in MergedItems).
// so better to use partial meta here
func genHash() -> String {
"\(item.meta.itemId) \(item.meta.updatedAt.hashValue) \(item.reactions.count) \(item.meta.isRcvNew) \(item.text.hash) \(unreadBefore) \(prevItem?.id ?? -1) \(nextItem?.id ?? -2)"
"\(item.meta.itemId) \(item.meta.updatedAt.hashValue) \(item.meta.itemEdited) \(item.meta.itemDeleted?.hashValue ?? 0) \(item.meta.itemTimed?.hashValue ?? 0) \(item.meta.itemStatus.hashValue) \(item.meta.sentViaProxy ?? false) \(item.mergeCategory?.hashValue ?? 0) \(chatDirHash(item.chatDir)) \(item.reactions.hashValue) \(item.meta.isRcvNew) \(item.text.hash) \(item.file?.hashValue ?? 0) \(item.quotedItem?.itemId ?? 0) \(unreadBefore) \(prevItem?.id ?? 0) \(chatDirHash(prevItem?.chatDir)) \(prevItem?.mergeCategory?.hashValue ?? 0) \(nextItem?.id ?? 0) \(chatDirHash(nextItem?.chatDir)) \(nextItem?.mergeCategory?.hashValue ?? 0)"
}
}
+20 -4
View File
@@ -48,6 +48,7 @@ struct ChatView: View {
@State private var allowToDeleteSelectedMessagesForAll: Bool = false
@State private var allowLoadMoreItems: Bool = false
@State private var ignoreLoadingRequests: [Int64] = []
@State private var updateMergedItemsTask: Task<Void, Never>? = nil
@AppStorage(DEFAULT_TOOLBAR_MATERIAL) private var toolbarMaterial = ToolbarMaterial.defaultMaterial
@@ -473,6 +474,7 @@ struct ChatView: View {
forwardedChatItems: $forwardedChatItems,
reveal: { reveal in
mergedItem.reveal(reveal, $revealedItems)
updateMergedItemsTask?.cancel()
mergedItems = MergedItems.create(ItemsModel.shared.reversedChatItems, chat.chatStats.unreadCount, revealedItems, ItemsModel.shared.chatState)
}
)
@@ -494,12 +496,23 @@ struct ChatView: View {
}
}
.onChange(of: im.reversedChatItems) { items in
mergedItems = MergedItems.create(items, chat.chatStats.unreadCount, revealedItems, ItemsModel.shared.chatState)
updateMergedItemsTask?.cancel()
updateMergedItemsTask = Task {
let items = MergedItems.create(items, chat.chatStats.unreadCount, revealedItems, ItemsModel.shared.chatState)
if Task.isCancelled {
return
}
await MainActor.run {
mergedItems = items
}
}
}
.onChange(of: revealedItems) { revealed in
updateMergedItemsTask?.cancel()
mergedItems = MergedItems.create(im.reversedChatItems, chat.chatStats.unreadCount, revealed, ItemsModel.shared.chatState)
}
.onChange(of: chat.chatStats.unreadCount) { unreadCount in
updateMergedItemsTask?.cancel()
mergedItems = MergedItems.create(im.reversedChatItems, unreadCount, revealedItems, ItemsModel.shared.chatState)
}
.onChange(of: chat.id) { _ in
@@ -913,7 +926,9 @@ struct ChatView: View {
private func loadChatItems(_ cInfo: ChatInfo, _ pagination: ChatPagination, _ visibleItemIndexesNonReversed: @escaping () -> ClosedRange<Int> = { 0 ... 0 }) async -> Bool {
if loadingMoreItems { return false }
loadingMoreItems = true
await MainActor.run {
loadingMoreItems = true
}
var chatItemsAvailable = true
var itemsCountChanged = false
// Load additional items until the page is +50 large after merging
@@ -1049,7 +1064,7 @@ struct ChatView: View {
} else {
nil
}
let showAvatar = if case .grouped = merged { shouldShowAvatar(item, listItem.nextItem) } else { true }
let showAvatar = shouldShowAvatar(item, listItem.nextItem)
let itemSeparation: ItemSeparation
let prevItemSeparationLargeGap: Bool
let single = switch merged {
@@ -1084,7 +1099,8 @@ struct ChatView: View {
}
.onAppear {
// LALAL
//return ()
return ()
if markedRead {
return
} else {
+27 -11
View File
@@ -61,7 +61,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
} else {
// when tableView is dragging and new items are added, scroll position cannot be set correctly
// so it's better to just wait until dragging ends
if !mergedItems.splits.isEmpty && controller.tableView.isDragging/* && !controller.tableView.isDecelerating*/ {
if !controller.useSmoothScrolling && !mergedItems.splits.isEmpty && controller.tableView.isDragging/* && !controller.tableView.isDecelerating*/ {
controller.runBlockOnEndDecelerating = {
Task {
let prevSnapshot = controller.dataSource.snapshot()
@@ -71,9 +71,9 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
controller.updateFloatingButtons.send()
return
}
await MainActor.run {
//await MainActor.run {
controller.update(mergedItems.items, mergedItems.snapshot, prevSnapshot)
}
//}
}
}
} else {
@@ -89,7 +89,9 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
controller.updateFloatingButtons.send()
return
}
controller.update(mergedItems.items, mergedItems.snapshot, prevSnapshot)
//await MainActor.run {
controller.update(mergedItems.items, mergedItems.snapshot, prevSnapshot)
//}
}
}
}
@@ -114,7 +116,8 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
private var runBlockOnEndScrolling: (() -> Void)? = nil
private let useSmoothScrolling = false
let useSmoothScrolling = false
var preloading = false
init(representer: ReverseList) {
self.representer = representer
@@ -305,6 +308,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
let wasFirstVisibleOffset = listState?.firstVisibleItemOffset ?? 0
// Sets content offset on initial load
logger.debug("LALAL STEP 4")
tableView.panGestureRecognizer.isEnabled = true
if wasCount == 0 {
dataSource.apply(
snapshot,
@@ -399,9 +403,11 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
updateFloatingButtons.send()
if let listState = self.getListState(representer.mergedItems.items) {
if runBlockOnEndDecelerating != nil && nearSplit(listState, representer.mergedItems) {
stopScrolling()
if let block = runBlockOnEndDecelerating, nearSplit(remaining: 40, listState, representer.mergedItems) {
tableView.panGestureRecognizer.isEnabled = false
block()
}
logger.debug("LALAL IN SPLIT OR NO \(self.nearSplit(remaining: 40, listState, self.representer.mergedItems)) \(String(describing: self.representer.mergedItems.splits))")
preloadIfNeeded(listState)
}
}
@@ -414,14 +420,16 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
}
}
func stopScrolling() {
func stopScrolling(disable: Bool = false) {
tableView.setContentOffset(self.tableView.contentOffset, animated: false)
if disable {
tableView.panGestureRecognizer.isEnabled = false
}
}
func nearSplit(_ listState: ListState, _ mergedItems: MergedItems) -> Bool {
func nearSplit(remaining: Int, _ listState: ListState, _ mergedItems: MergedItems) -> Bool {
if mergedItems.splits.isEmpty { return false }
let remaining = 10
let firstVisibleIndex = listState.firstVisibleItemIndex
let lastVisibleIndex = listState.lastVisibleItemIndex
for split in mergedItems.splits {
@@ -435,6 +443,10 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
let containsInRange = split.indexRangeInParentItems.contains(firstVisibleIndex)
if containsInRange {
if lastVisibleIndex > (split.indexRangeInParentItems.upperBound - remaining) {
// situation when there is nothing to load from top
if self.representer.ignoreLoadingRequests.contains(where: { $0 == mergedItems.items.last?.oldest().item.id } ) {
return false
}
return true
}
if firstVisibleIndex < (split.indexRangeInParentItems.lowerBound + remaining) {
@@ -543,10 +555,14 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
}
func preloadIfNeeded(_ state: ListState) {
if representer.scrollState == .atDestination, prevFirstVisible != state.firstVisibleItemIndex {
if representer.scrollState == .atDestination, prevFirstVisible != state.firstVisibleItemIndex, !preloading {
logger.debug("LALAL LOADING before \(String(describing: self.representer.scrollState))")
prevFirstVisible = state.firstVisibleItemIndex
Task {
preloading = true
defer {
preloading = false
}
let mergedItems = self.representer.mergedItems
await preloadItems(mergedItems, self.representer.allowLoadMoreItems, state, self.representer.$ignoreLoadingRequests) { pagination in
logger.debug("LALAL LOADING INSIDE")