mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
wip
This commit is contained in:
@@ -52,8 +52,13 @@ class ItemsModel: ObservableObject {
|
||||
static let shared = ItemsModel()
|
||||
private let publisher = ObservableObjectPublisher()
|
||||
private var bag = Set<AnyCancellable>()
|
||||
var chatItemIds = Set<ChatItem.ID>()
|
||||
var reversedChatItems: [ChatItem] = [] {
|
||||
willSet { publisher.send() }
|
||||
willSet {
|
||||
chatItemIds.removeAll()
|
||||
chatItemIds.formUnion(newValue.map { $0.id })
|
||||
publisher.send()
|
||||
}
|
||||
}
|
||||
var itemAdded = false {
|
||||
willSet { publisher.send() }
|
||||
|
||||
@@ -346,6 +346,7 @@ struct FramedItemView: View {
|
||||
|
||||
private func loadItemsAround(_ cInfo: ChatInfo, _ chatItemId: Int64) async -> [ChatItem]? {
|
||||
do {
|
||||
let im = ItemsModel.shared
|
||||
var reversedPage = Array<ChatItem>()
|
||||
let pagination: ChatPagination = .around(chatItemId: chatItemId, count: loadItemsPerPage * 2)
|
||||
let (chatItems, gap) = try await apiGetChatItems(
|
||||
@@ -355,13 +356,15 @@ struct FramedItemView: View {
|
||||
search: ""
|
||||
)
|
||||
|
||||
reversedPage.append(contentsOf: chatItems.reversed())
|
||||
let dedupedChatItems = chatItems.filter { !im.chatItemIds.contains($0.id) }
|
||||
reversedPage.append(contentsOf: dedupedChatItems.reversed())
|
||||
|
||||
await MainActor.run {
|
||||
ItemsModel.shared.reversedChatItems.append(contentsOf: reversedPage)
|
||||
if let size = gap {
|
||||
ItemsModel.shared.gap = ChatGap(index: reversedPage.count, size: size)
|
||||
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)
|
||||
}
|
||||
|
||||
return reversedPage
|
||||
|
||||
@@ -443,8 +443,8 @@ struct ChatView: View {
|
||||
forwardedChatItems: $forwardedChatItems
|
||||
)
|
||||
.id(ci.id) // Required to trigger `onAppear` on iOS15
|
||||
} loadPage: {
|
||||
loadChatItems(cInfo)
|
||||
} loadPage: { pagination in
|
||||
loadChatItems(cInfo, pagination)
|
||||
}
|
||||
.opacity(ItemsModel.shared.isLoading ? 0 : 1)
|
||||
.padding(.vertical, -InvertedTableView.inset)
|
||||
@@ -857,7 +857,7 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func loadChatItems(_ cInfo: ChatInfo) {
|
||||
private func loadChatItems(_ cInfo: ChatInfo, _ pagination: ChatPagination = .initial(count: loadItemsPerPage)) {
|
||||
Task {
|
||||
if loadingItems || firstPage { return }
|
||||
loadingItems = true
|
||||
@@ -866,26 +866,50 @@ struct ChatView: View {
|
||||
var chatItemsAvailable = true
|
||||
// Load additional items until the page is +50 large after merging
|
||||
while chatItemsAvailable && filtered(reversedPage).count < loadItemsPerPage {
|
||||
let pagination: ChatPagination =
|
||||
if let lastItem = reversedPage.last ?? im.reversedChatItems.last {
|
||||
.before(chatItemId: lastItem.id, count: loadItemsPerPage)
|
||||
} else {
|
||||
.last(count: loadItemsPerPage)
|
||||
}
|
||||
let chatPagination: ChatPagination = switch pagination {
|
||||
case let .before(chatItemId, count): .before(chatItemId: reversedPage.last?.id ?? chatItemId, count: count)
|
||||
case let .last(count): .last(count: count)
|
||||
case let .initial(count): .initial(count: count)
|
||||
case let .after(chatItemId, count):
|
||||
.after(chatItemId: reversedPage.first?.id ?? chatItemId, count: count)
|
||||
case .around(_, _): throw RuntimeError("Unsupported pagination type for loading chat items: \(pagination)")
|
||||
}
|
||||
|
||||
let (chatItems, _) = try await apiGetChatItems(
|
||||
type: cInfo.chatType,
|
||||
id: cInfo.apiId,
|
||||
pagination: pagination,
|
||||
pagination: chatPagination,
|
||||
search: searchText
|
||||
)
|
||||
chatItemsAvailable = !chatItems.isEmpty
|
||||
reversedPage.append(contentsOf: chatItems.reversed())
|
||||
}
|
||||
let dedupedreversePage = reversedPage.filter { !im.chatItemIds.contains($0.id) }
|
||||
await MainActor.run {
|
||||
if reversedPage.count == 0 {
|
||||
firstPage = true
|
||||
} else {
|
||||
im.reversedChatItems.append(contentsOf: reversedPage)
|
||||
|
||||
switch pagination {
|
||||
case .before, .last, .initial:
|
||||
im.reversedChatItems.append(contentsOf: dedupedreversePage)
|
||||
case let .after(chatItemId, _):
|
||||
let index = im.reversedChatItems.firstIndex { $0.id == chatItemId }
|
||||
logger.error("[scrolling] setting: \(dedupedreversePage.count) \(index ?? -1)")
|
||||
|
||||
if let index {
|
||||
if let gap = im.gap {
|
||||
let size = gap.size - dedupedreversePage.count
|
||||
if size > 0 {
|
||||
im.gap = ChatGap(index: gap.index, size: size)
|
||||
} else {
|
||||
im.gap = nil
|
||||
}
|
||||
}
|
||||
im.reversedChatItems.insert(contentsOf: dedupedreversePage, at: index)
|
||||
}
|
||||
case .around(_, _): break
|
||||
}
|
||||
}
|
||||
loadingItems = false
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
|
||||
/// Closure, that returns user interface for a given item
|
||||
let content: (ChatItem) -> Content
|
||||
|
||||
let loadPage: () -> Void
|
||||
let loadPage: (_ pagination: ChatPagination) -> Void
|
||||
|
||||
func makeUIViewController(context: Context) -> Controller {
|
||||
Controller(representer: self)
|
||||
@@ -41,7 +41,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
|
||||
controller.scrollToUnread(to: items.first(where: { $0.id == id }))
|
||||
}
|
||||
} else {
|
||||
logger.error("[scrolling] not scrolling gap: (\(gap?.index ?? -1), \(gap?.size ?? 0)")
|
||||
logger.error("[scrolling] not scrolling gap: (\(gap?.index ?? -1), \(gap?.size ?? 0))")
|
||||
controller.update(items: items, gap: gap)
|
||||
}
|
||||
}
|
||||
@@ -85,11 +85,12 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
|
||||
if self.representer.scrollState == .atDestination {
|
||||
if indexPath.item > self.itemCount - preloadItem, let item = self.getItemAtPath(indexPath: IndexPath(row: self.itemCount - 1, section: 0)) {
|
||||
logger.error("[scrolling] requesting page \(item.text)")
|
||||
self.representer.loadPage()
|
||||
self.representer.loadPage(.before(chatItemId: item.id, count: loadItemsPerPage))
|
||||
} else if let item = self.getFirstItemBeforePlacholder(indexPath) {
|
||||
logger.error("[scrolling] needs items in top \(item.text)")
|
||||
// TODO: Cleanup, this should never be possible
|
||||
} else if let item = self.getFirstItemAfterPlacholder(indexPath) {
|
||||
logger.error("[scrolling] needs items in bottom \(item.text)")
|
||||
self.representer.loadPage(.after(chatItemId: item.id, count: loadItemsPerPage))
|
||||
}
|
||||
}
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseId, for: indexPath)
|
||||
|
||||
Reference in New Issue
Block a user