This commit is contained in:
Avently committed 2024-12-27 08:47:12 -08:00
1 parent 83f478e7ba
commit e2b9e162eb
5 files changed
+111 -38

No files matched your search

@@ -11,17 +11,45 @@ import SimpleXChat
func loadLastItems(_ loadingMoreItems: Binding<Bool>, _ chatInfo: ChatInfo) {
//return ()
if ItemsModel.shared.chatState.totalAfter == 0 {
return
}
loadingMoreItems.wrappedValue = true
Task {
try? await Task.sleep(nanoseconds: 2500_000000)
if ItemsModel.shared.chatState.totalAfter == 0 || ChatModel.shared.chatId != chatInfo.id {
try? await Task.sleep(nanoseconds: 1500_000000)
if ChatModel.shared.chatId != chatInfo.id {
await MainActor.run {
loadingMoreItems.wrappedValue = false
}
return
}
await MainActor.run {
loadingMoreItems.wrappedValue = true
}
await apiLoadMessages(chatInfo.chatType, chatInfo.apiId, ChatPagination.last(count: 50), ItemsModel.shared.chatState)
await MainActor.run {
loadingMoreItems.wrappedValue = false
}
}
}
func preloadItems(_ mergedItems: MergedItems, _ state: ListState, _ ignoreLoadingRequests: Binding<[Int64]>, _ loadItems: @escaping (ChatPagination) -> Void) {
let remaining = ChatPagination.UNTIL_PRELOAD_COUNT
let firstVisibleIndex = state.firstVisibleItemIndex
preloadItemsAfter()
func preloadItemsAfter() {
let items: [ChatItem] = ItemsModel.shared.reversedChatItems.reversed()
let splits = mergedItems.splits
let split = splits.last(where: { $0.indexRangeInParentItems.contains(firstVisibleIndex) })
// we're inside a splitRange (top --- [end of the splitRange --- we're here --- start of the splitRange] --- bottom)
logger.debug("LALAL PRELOAD AFTER \(String(describing: split)) \(firstVisibleIndex) \(items.count - 1 - (split?.indexRangeInReversed.lowerBound ?? -1))")
if let split, split.indexRangeInParentItems.lowerBound + remaining > firstVisibleIndex {
let index = items.count - 1 - split.indexRangeInReversed.lowerBound
if index >= 0 {
let loadFromItemId = items[index].id
loadItems(.after(chatItemId: loadFromItemId, count: ChatPagination.PRELOAD_COUNT))
}
}
}
}
+12 -3
View File
@@ -47,6 +47,7 @@ struct ChatView: View {
@State private var selectedChatItems: Set<Int64>? = nil
@State private var showDeleteSelectedMessages: Bool = false
@State private var allowToDeleteSelectedMessagesForAll: Bool = false
@State private var ignoreLoadingRequests: [Int64] = []
@AppStorage(DEFAULT_TOOLBAR_MATERIAL) private var toolbarMaterial = ToolbarMaterial.defaultMaterial
@@ -429,12 +430,19 @@ struct ChatView: View {
.map { $0.element }
}
var searchValueIsEmpty: Bool {
get {
searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
}
private func chatItemsList() -> some View {
let cInfo = chat.chatInfo
return GeometryReader { g in
let _ = logger.debug("LALAL RELOAD \(im.reversedChatItems.count)")
ReverseList(items: im.reversedChatItems, mergedItems: $mergedItems, revealedItems: $revealedItems, unreadCount: Binding.constant(chat.chatStats.unreadCount), scrollState: $scrollModel.state) { index, mergedItem in
// LALAL CAN I CHANGE BINDING LIKE THIS IN ignoreLoadingRequests?
ReverseList(items: im.reversedChatItems, mergedItems: $mergedItems, revealedItems: $revealedItems, unreadCount: Binding.constant(chat.chatStats.unreadCount), scrollState: $scrollModel.state, ignoreLoadingRequests: searchValueIsEmpty ? $ignoreLoadingRequests : Binding.constant([])) { index, mergedItem in
let ci = switch mergedItem {
case let .single(item, _): item.item
case let .grouped(items, _, _, _, _, _, _): items.boxedValue.last!.item
@@ -892,7 +900,7 @@ struct ChatView: View {
var chatItemsAvailable = true
var itemsCountChanged = false
// Load additional items until the page is +50 large after merging
while chatItemsAvailable && filtered(im.reversedChatItems).count < loadItemsPerPage {
//while chatItemsAvailable && filtered(im.reversedChatItems).count < loadItemsPerPage {
let oldCount = im.reversedChatItems.count
await apiLoadMessages(
cInfo.chatType,
@@ -904,7 +912,8 @@ struct ChatView: View {
)
itemsCountChanged = im.reversedChatItems.count != oldCount
chatItemsAvailable = itemsCountChanged
}
//}
logger.debug("LALAL ITEMCOUNTCHANGED \(itemsCountChanged) \(oldCount) \(im.reversedChatItems.count)")
await MainActor.run {
if !itemsCountChanged {
firstPage = true
@@ -547,6 +547,11 @@ struct ComposeView: View {
if case let .voicePreview(_, duration) = composeState.preview {
voiceMessageRecordingTime = TimeInterval(duration)
}
// Task {
// for i in 201 ... 400 {
// await sendMessageAsync("\(i)", live: false, ttl: nil)
// }
// }
}
}
+57 -30
View File
@@ -18,8 +18,7 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
@Binding var unreadCount: Int
@Binding var scrollState: ReverseListScrollModel.State
@State private var itemsUpdaterTask: Task<Void, Never>? = nil
@Binding var ignoreLoadingRequests: [Int64]
/// Closure, that returns user interface for a given item
/// Index, merged item
@@ -45,26 +44,14 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
controller.scroll(to: 0, position: .top)
}
} else {
itemsUpdaterTask?.cancel()
// 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 controller.tableView.isDragging && !controller.tableView.isDecelerating {
DispatchQueue.main.async {
itemsUpdaterTask = Task {
while controller.tableView.isDragging && !controller.tableView.isDecelerating {
do {
try await Task.sleep(nanoseconds: 100_000000)
} catch {
return
}
}
await MainActor.run {
controller.update(items: items)
}
}
if controller.tableView.isDragging/* && !controller.tableView.isDecelerating*/ {
controller.runBlockOnEndDecelerating = {
controller.update(items: items)
}
} else {
controller.runBlockOnEndDecelerating = nil
controller.update(items: items)
}
}
@@ -88,6 +75,8 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
private let updateFloatingButtons = PassthroughSubject<Void, Never>()
private var bag = Set<AnyCancellable>()
var runBlockOnEndDecelerating: (() -> Void)? = nil
private var scrollToRowOnAppear = 0
init(representer: ReverseList) {
@@ -113,15 +102,26 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
)
}
var prevFirstVisible = -1
// 3. Configure data source
self.dataSource = UITableViewDiffableDataSource<Section, Int>(
tableView: tableView
) { (tableView, indexPath, item) -> UITableViewCell? in
if indexPath.item > self.itemCount - 8 {
//if indexPath.item > self.itemCount - 8 {
logger.debug("LALAL ITEM \(indexPath.item)")
let pagination = ChatPagination.last(count: 0)
self.representer.loadItems(pagination, { self.visibleItemIndexesNonReversed(Binding.constant(self.representer.mergedItems)) })
}
Task {
// do not put it outside Task because it will be stackoverflow error
if let state = self.getListState(), prevFirstVisible != state.firstVisibleItemIndex {
prevFirstVisible = state.firstVisibleItemIndex
logger.debug("LALAL LOADING before")
preloadItems(self.representer.mergedItems, state, self.representer.$ignoreLoadingRequests) { pagination in
logger.debug("LALAL LOADING INSIDE")
self.representer.loadItems(pagination, { self.visibleItemIndexesNonReversed(Binding.constant(self.representer.mergedItems)) })
}
}
}
//}
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseId, for: indexPath)
if #available(iOS 16.0, *) {
cell.contentConfiguration = UIHostingConfiguration { self.representer.content(indexPath.item, self.itemsInPrevSnapshot[item]!) }
@@ -186,6 +186,11 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
NotificationCenter.default.post(name: .chatViewWillBeginScrolling, object: nil)
}
override public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
runBlockOnEndDecelerating?()
runBlockOnEndDecelerating = nil
}
/// depending on tableView layout phase conditions, it can already have known size or not. Not possible to correctly scroll to required
/// item if the size is unknown
func scrollToRowWhenKnowSize(_ row: Int) {
@@ -253,13 +258,17 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
func update(items: [ChatItem]) {
var prevSnapshot = dataSource.snapshot()
let wasCount = prevSnapshot.numberOfItems
let insertedOneNewestItem = wasCount != 0 && representer.mergedItems.items.count - wasCount == 1 && prevSnapshot.itemIdentifiers.first!.hashValue == self.representer.mergedItems.items[1].hashValue
let willBeCount = representer.mergedItems.items.count
let c = 13
let insertedOneNewestItem = wasCount != 0 && willBeCount - wasCount == c && prevSnapshot.itemIdentifiers.first!.hashValue == self.representer.mergedItems.items[c].hashValue
logger.debug("LALAL WAS \(wasCount) will be \(self.representer.mergedItems.items.count)")
//self.representer.mergedItems = MergedItems.create(items, representer.unreadCount, representer.revealedItems, ItemsModel.shared.chatState)
let snapshot: NSDiffableDataSourceSnapshot<Section, Int>
let itemsInCurrentSnapshot: Dictionary<Int, MergedItem>
if insertedOneNewestItem {
prevSnapshot.insertItems([representer.mergedItems.items.first!.hashValue], beforeItem: prevSnapshot.itemIdentifiers.first!)
for i in 0 ..< c {
prevSnapshot.insertItems([representer.mergedItems.items[c - i].hashValue], beforeItem: prevSnapshot.itemIdentifiers.first!)
}
var new = itemsInPrevSnapshot
new[representer.mergedItems.items.first!.hashValue] = representer.mergedItems.items.first!
itemsInCurrentSnapshot = new
@@ -305,8 +314,10 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
}
} else if wasCount != snapshot.numberOfItems {
logger.debug("LALAL drag \(self.tableView.isDragging), decel \(self.tableView.isDecelerating)")
// tableView.panGestureRecognizer.isEnabled = false
// logger.debug("LALAL drag2 \(self.tableView.isDragging), decel \(self.tableView.isDecelerating)")
if tableView.isDecelerating {
// CATransaction.begin()
itemsInPrevSnapshot = itemsInCurrentSnapshot
tableView.beginUpdates()
dataSource.apply(
@@ -314,16 +325,18 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
animatingDifferences: false
)
tableView.endUpdates()
// CATransaction.commit()
tableView.panGestureRecognizer.isEnabled = true
} else {
itemsInPrevSnapshot = itemsInCurrentSnapshot
dataSource.apply(
snapshot,
animatingDifferences: false
)
if snapshot.itemIdentifiers[0] == prevSnapshot.itemIdentifiers[0] {
//if snapshot.itemIdentifiers[0] == prevSnapshot.itemIdentifiers[0] {
// added new items to top
} else {
//} else {
// added new items to bottom
// logger.debug("LALAL WAS HEIGHT \(wasContentHeight) now \(self.tableView.contentSize.height), offset was \(wasOffset), now \(self.tableView.contentOffset.y), will be \(self.tableView.contentOffset.y + (self.tableView.contentSize.height - wasContentHeight)), countDiff \(countDiff), wasVisibleRow \(wasFirstVisibleRow), wasFirstVisibleOffset \(wasFirstVisibleOffset)")
self.tableView.scrollToRow(
@@ -337,10 +350,11 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
)
let state = getListState()!
logger.debug("LALAL NOW FIRST VISIBLE \(state.firstVisibleItemIndex) \(state.firstVisibleItemOffset)")
}
//}
}
}
updateFloatingButtons.send()
return
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
@@ -348,8 +362,9 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
}
func getListState() -> ListState? {
logger.debug("LALAL VISIBLE ROWS \((self.tableView.indexPathsForVisibleRows ?? []).map({ $0.row }))")
if let visibleRows = tableView.indexPathsForVisibleRows,
visibleRows.last?.item ?? 0 < representer.mergedItems.items.count {
visibleRows.last?.row ?? 0 < representer.mergedItems.items.count {
let scrollOffset: Double = tableView.contentOffset.y + InvertedTableView.inset
let topItemDate: Date? =
if let lastVisible = visibleRows.last(where: { isVisible(indexPath: $0) }) {
@@ -364,11 +379,11 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
let lastVisible = visibleRows.last(where: { isVisible(indexPath: $0) })
let bottomItemId: ChatItem.ID? =
if let firstVisible {
representer.mergedItems.items[firstVisible.item].newest().item.id
representer.mergedItems.items[firstVisible.row].newest().item.id
} else {
nil
}
return ListState(scrollOffset: scrollOffset, topItemDate: topItemDate, bottomItemId: bottomItemId, firstVisibleItemIndex: firstVisible?.item ?? 0, lastVisibleItemIndex: lastVisible?.item ?? 0, firstVisibleItemOffset: firstVisibleOffset ?? 0)
return ListState(scrollOffset: scrollOffset, topItemDate: topItemDate, bottomItemId: bottomItemId, firstVisibleItemIndex: firstVisible?.row ?? 0, lastVisibleItemIndex: lastVisible?.row ?? 0, firstVisibleItemOffset: firstVisibleOffset ?? 0)
}
return nil
}
@@ -537,4 +552,16 @@ class InvertedTableView: UITableView {
override var adjustedContentInset: UIEdgeInsets {
Self.insets
}
// override var contentOffset: CGPoint {
// get { super.contentOffset }
// set {
// logger.debug("LALAL SET OFFSET \(newValue.y)")
// if newValue.y <= 0 {
// return
// }
// super.contentOffset = newValue
// }
// }
}
+4
View File
@@ -1183,6 +1183,10 @@ struct NewUser: Encodable {
}
public enum ChatPagination {
public static let INITIAL_COUNT = 50
public static let PRELOAD_COUNT = 50
public static let UNTIL_PRELOAD_COUNT = 50
case last(count: Int)
case after(chatItemId: Int64, count: Int)
case before(chatItemId: Int64, count: Int)