This commit is contained in:
Diogo
2024-11-09 22:00:11 +00:00
parent 4847d2222f
commit 1b2d7e93f7
5 changed files with 19 additions and 63 deletions
+5 -10
View File
@@ -322,15 +322,15 @@ let loadItemsPerPage = 100
let preloadItem = 25
let idealChatListSize = 300
func apiGetChat(type: ChatType, id: Int64, search: String = "") async throws -> (Chat, Int?) {
func apiGetChat(type: ChatType, id: Int64, search: String = "") async throws -> Chat {
let r = await chatSendCmd(.apiGetChat(type: type, id: id, pagination: .initial(count: loadItemsPerPage), search: search))
if case let .apiChat(_, chat, gap) = r { return (Chat.init(chat), gap) }
if case let .apiChat(_, chat, _) = r { return Chat.init(chat) }
throw r
}
func apiGetChatItems(type: ChatType, id: Int64, pagination: ChatPagination, search: String = "") async throws -> ([ChatItem], Int?) {
func apiGetChatItems(type: ChatType, id: Int64, pagination: ChatPagination, search: String = "") async throws -> [ChatItem] {
let r = await chatSendCmd(.apiGetChat(type: type, id: id, pagination: pagination, search: search))
if case let .apiChat(_, chat, gap) = r { return (chat.chatItems, gap) }
if case let .apiChat(_, chat, _) = r { return chat.chatItems }
if case .chatCmdError(_, _) = r {
if case .chatError(_, let chatError) = r {
if case .errorStore(let storeError) = chatError {
@@ -355,14 +355,9 @@ func loadChat(chat: Chat, search: String = "", clearItems: Bool = true) async {
im.gap = nil
}
}
let (chat, gap) = try await apiGetChat(type: cInfo.chatType, id: cInfo.apiId, search: search)
let chat = try await apiGetChat(type: cInfo.chatType, id: cInfo.apiId, search: search)
await MainActor.run {
im.reversedChatItems = chat.chatItems.reversed()
if let gap = gap {
im.gap = ChatGap(index: loadItemsPerPage, size: gap)
} else {
im.gap = nil
}
m.updateChatInfo(chat.chatInfo)
}
} catch let error {
@@ -349,7 +349,7 @@ struct FramedItemView: View {
let im = ItemsModel.shared
var reversedPage = Array<ChatItem>()
let pagination: ChatPagination = .around(chatItemId: chatItemId, count: loadItemsPerPage * 2)
let (chatItems, gap) = try await apiGetChatItems(
let chatItems = try await apiGetChatItems(
type: cInfo.chatType,
id: cInfo.apiId,
pagination: pagination,
@@ -366,18 +366,12 @@ struct FramedItemView: View {
}
let itemCount = im.reversedChatItems.count
if let size = gap, size - itemCount > 0 {
im.gap = ChatGap(index: itemCount, size: size - itemCount)
}
im.reversedChatItems.append(contentsOf: reversedPage)
}
if (itemsToDrop.count > 0) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Task {
if let g = im.gap {
im.gap = ChatGap(index: g.index - itemsToDrop.count, size: g.size + itemsToDrop.count)
}
im.reversedChatItems.removeAll(where: { itemsToDrop.contains($0.id) })
}
}
+2 -21
View File
@@ -427,7 +427,7 @@ struct ChatView: View {
let cInfo = chat.chatInfo
let mergedItems = filtered(im.reversedChatItems)
return GeometryReader { g in
ReverseList(items: mergedItems, gap: im.gap, scrollState: $scrollModel.state, initialChatItem: $initialChatItem) { ci in
ReverseList(items: mergedItems, scrollState: $scrollModel.state, initialChatItem: $initialChatItem) { ci in
let voiceNoFrame = voiceWithoutFrame(ci)
let maxWidth = cInfo.chatType == .group
? voiceNoFrame
@@ -485,7 +485,6 @@ struct ChatView: View {
scrollModel.scrollToBottom()
if let g = im.gap {
let sliceSize = min(g.index, idealChatListSize)
im.gap = nil
im.reversedChatItems = Array(im.reversedChatItems[..<sliceSize])
}
}
@@ -893,7 +892,6 @@ struct ChatView: View {
loadingItems = true
do {
var reversedPage = Array<ChatItem>()
var apiGap: Int? = nil
var chatItemsAvailable = true
// Load additional items until the page is +50 large after merging
while chatItemsAvailable && filtered(reversedPage).count < loadItemsPerPage {
@@ -906,13 +904,12 @@ struct ChatView: View {
case .around(_, _): throw RuntimeError("Unsupported pagination type for loading chat items: \(pagination)")
}
let (chatItems, gap) = try await apiGetChatItems(
let chatItems = try await apiGetChatItems(
type: cInfo.chatType,
id: cInfo.apiId,
pagination: chatPagination,
search: searchText
)
apiGap = gap
chatItemsAvailable = !chatItems.isEmpty
reversedPage.append(contentsOf: chatItems.reversed())
}
@@ -928,28 +925,12 @@ struct ChatView: View {
case .before(_, _):
if im.reversedChatItems.count + dedupedreversePage.count > idealChatListSize,
dedupedreversePage.count <= loadItemsPerPage {
if let gap = im.gap {
im.gap = ChatGap(index: gap.index, size: gap.size + dedupedreversePage.count)
} else {
im.gap = ChatGap(index: loadItemsPerPage, size: dedupedreversePage.count)
}
im.reversedChatItems.removeSubrange(loadItemsPerPage..<loadItemsPerPage + dedupedreversePage.count)
}
im.reversedChatItems.append(contentsOf: dedupedreversePage)
case let .after(chatItemId, _):
let index = im.reversedChatItems.firstIndex { $0.id == chatItemId }
if let index {
if let gap = im.gap {
let size = max(0, (apiGap ?? 0) - index)
if size > 0 {
im.gap = ChatGap(index: gap.index, size: size)
if im.reversedChatItems.count + dedupedreversePage.count - gap.index > idealChatListSize {
im.reversedChatItems.removeLast(dedupedreversePage.count)
}
} else {
im.gap = nil
}
}
im.reversedChatItems.insert(contentsOf: dedupedreversePage, at: index)
}
case .around(_, _): break
@@ -340,7 +340,7 @@ struct GroupMemberInfoView: View {
InfoViewButton(image: "message.fill", title: "message", width: width) {
Task {
do {
let (chat, _) = try await apiGetChat(type: .direct, id: contactId)
let chat = try await apiGetChat(type: .direct, id: contactId)
chatModel.addChat(chat)
ItemsModel.shared.loadOpenChat(chat.id) {
dismissAllSheets(animated: true)
+10 -24
View File
@@ -13,7 +13,6 @@ import SimpleXChat
/// A List, which displays it's items in reverse order - from bottom to top
struct ReverseList<Content: View>: UIViewControllerRepresentable {
let items: Array<ChatItem>
let gap: ChatGap?
@Binding var scrollState: ReverseListScrollModel.State
@Binding var initialChatItem: ChatItem?
@@ -40,7 +39,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
controller.scroll(to: 0, position: .top)
}
} else {
controller.update(items: items, gap: gap)
controller.update(items: items)
}
}
@@ -52,7 +51,6 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
private var itemCount: Int = 0
private let updateFloatingButtons = PassthroughSubject<Void, Never>()
private var bag = Set<AnyCancellable>()
private var renderedItems = Array<ChatItem>()
init(representer: ReverseList) {
self.representer = representer
@@ -222,27 +220,15 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
}
}
func update(items: [ChatItem], gap: ChatGap?) {
func update(items: [ChatItem]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, ChatItem>()
let originalSize = renderedItems.count
if let gap = gap {
var itemsCopy = items
let blanks = (0..<20).map { index in
// Using existing text instead of random rumble or empty text does make long scroll look natural.
let sourceItem = items[index % items.count]
return ChatItem.placeholder(idx: index + 1, text: sourceItem.text, chatDir: sourceItem.chatDir)
}
itemsCopy.insert(contentsOf: blanks, at: gap.index)
renderedItems = itemsCopy
} else {
renderedItems = items
}
let originalSize = tableView.numberOfRows(inSection: 0)
snapshot.appendSections([.main])
snapshot.appendItems(renderedItems)
snapshot.appendItems(items)
dataSource.defaultRowAnimation = .none
let countDiff = max(0, renderedItems.count - originalSize)
if tableView.contentOffset.y == 0, originalSize > countDiff {
let countDiff = max(0, items.count - originalSize)
if tableView.contentOffset.y == 100, originalSize < items.count, originalSize > 0 {
dataSource.apply(
snapshot,
animatingDifferences: false
@@ -269,7 +255,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
animated: false
)
}
itemCount = renderedItems.count
itemCount = items.count
updateFloatingButtons.send()
}
@@ -279,18 +265,18 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
func getListState() -> ListState? {
if let visibleRows = tableView.indexPathsForVisibleRows,
visibleRows.last?.item ?? 0 < renderedItems.count {
visibleRows.last?.item ?? 0 < representer.items.count {
let scrollOffset: Double = tableView.contentOffset.y + InvertedTableView.inset
let topItemDate: Date? =
if let lastVisible = visibleRows.last(where: { isVisible(indexPath: $0) }) {
renderedItems[lastVisible.item].meta.itemTs
representer.items[lastVisible.item].meta.itemTs
} else {
nil
}
let bottomItemId: ChatItem.ID? =
if let firstVisible = visibleRows.first(where: { isVisible(indexPath: $0) }) {
renderedItems[firstVisible.item].id
representer.items[firstVisible.item].id
} else {
nil
}