mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
send tuple, reduce lookups
This commit is contained in:
@@ -454,50 +454,55 @@ struct ChatView: View {
|
||||
@Published var date: Date?
|
||||
@Published var isDateVisible: Bool = false
|
||||
var isReallyNearBottom: Bool { scrollOffset.value > 0 && scrollOffset.value < 500 }
|
||||
let visibleItems = PassthroughSubject<[String], Never>()
|
||||
let listState = PassthroughSubject<ListState, Never>()
|
||||
let scrollOffset = CurrentValueSubject<Double, Never>(0)
|
||||
|
||||
private var bag = Set<AnyCancellable>()
|
||||
|
||||
typealias ListState = (
|
||||
topItemDate: Date?,
|
||||
bottomItemId: ChatItem.ID?
|
||||
)
|
||||
|
||||
private struct ViewUpdate: Equatable {
|
||||
let unreadBelow: Int
|
||||
let date: Date?
|
||||
}
|
||||
|
||||
init() {
|
||||
// Date
|
||||
visibleItems
|
||||
listState
|
||||
.receive(on: DispatchQueue.global(qos: .background))
|
||||
.map { visibleItems -> Date? in
|
||||
if let viewId = visibleItems.last {
|
||||
ItemsModel.shared.reversedChatItems
|
||||
.first { $0.viewId == viewId }
|
||||
.map { Calendar.current.startOfDay(for: $0.meta.itemTs) }
|
||||
} else { nil }
|
||||
.map { listState -> ViewUpdate in
|
||||
let im = ItemsModel.shared
|
||||
return ViewUpdate(
|
||||
unreadBelow: {
|
||||
if let id = listState.bottomItemId,
|
||||
let index = im.reversedChatItems.firstIndex(where: { $0.id == id }) {
|
||||
im.reversedChatItems[..<index].reduce(into: 0) { unread, chatItem in
|
||||
if chatItem.isRcvNew { unread += 1 }
|
||||
}
|
||||
} else { 0 }
|
||||
}(),
|
||||
date: listState.topItemDate.map { Calendar.current.startOfDay(for: $0) }
|
||||
)
|
||||
}
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.date, on: self)
|
||||
.sink {
|
||||
self.unreadBelow = $0.unreadBelow
|
||||
self.date = $0.date
|
||||
}
|
||||
.store(in: &bag)
|
||||
|
||||
// Date visibility
|
||||
visibleItems
|
||||
listState
|
||||
.map { _ in self.setDate(visibility: true) }
|
||||
// Hide the date after 1 second of no scrolling
|
||||
.debounce(for: 1, scheduler: DispatchQueue.main)
|
||||
.sink { self.setDate(visibility: false) }
|
||||
.store(in: &bag)
|
||||
|
||||
// Unread Below
|
||||
visibleItems
|
||||
.receive(on: DispatchQueue.global(qos: .background))
|
||||
.map { itemIds in
|
||||
if let viewId = itemIds.first,
|
||||
let index = ItemsModel.shared.reversedChatItems.firstIndex(where: { $0.viewId == viewId }) {
|
||||
ItemsModel.shared.reversedChatItems[..<index].reduce(into: 0) { unread, chatItem in
|
||||
if chatItem.isRcvNew { unread += 1 }
|
||||
}
|
||||
} else { 0 }
|
||||
}
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.unreadBelow, on: self)
|
||||
.store(in: &bag)
|
||||
|
||||
// Is near bottom
|
||||
scrollOffset
|
||||
.map { $0 < 800 }
|
||||
|
||||
@@ -204,24 +204,31 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
|
||||
}
|
||||
|
||||
private func updateVisibleItems() {
|
||||
let fbm = ChatView.FloatingButtonModel.shared
|
||||
fbm.scrollOffset.send(tableView.contentOffset.y + InvertedTableView.inset)
|
||||
fbm.visibleItems.send(
|
||||
(tableView.indexPathsForVisibleRows ?? [])
|
||||
.compactMap { indexPath -> String? in
|
||||
guard let relativeFrame = tableView.superview?.convert(
|
||||
tableView.rectForRow(at: indexPath),
|
||||
from: tableView
|
||||
) else { return nil }
|
||||
// Checks that the cell is visible accounting for the added insets
|
||||
let isVisible =
|
||||
relativeFrame.maxY > InvertedTableView.inset &&
|
||||
relativeFrame.minY < tableView.frame.height - InvertedTableView.inset
|
||||
return indexPath.item < representer.items.count && isVisible
|
||||
? representer.items[indexPath.item].viewId
|
||||
: nil
|
||||
}
|
||||
)
|
||||
if let visibleRows = tableView.indexPathsForVisibleRows,
|
||||
visibleRows.last?.item ?? 0 < representer.items.count {
|
||||
let fbm = ChatView.FloatingButtonModel.shared
|
||||
fbm.scrollOffset.send(tableView.contentOffset.y + InvertedTableView.inset)
|
||||
fbm.listState.send((
|
||||
topItemDate: visibleRows
|
||||
.last { isVisible(indexPath: $0) }
|
||||
.map { representer.items[$0.item] }?
|
||||
.meta.itemTs,
|
||||
bottomItemId: visibleRows
|
||||
.first { isVisible(indexPath: $0) }
|
||||
.map { representer.items[$0.item] }?
|
||||
.id
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private func isVisible(indexPath: IndexPath) -> Bool {
|
||||
if let relativeFrame = tableView.superview?.convert(
|
||||
tableView.rectForRow(at: indexPath),
|
||||
from: tableView
|
||||
) {
|
||||
relativeFrame.maxY > InvertedTableView.inset &&
|
||||
relativeFrame.minY < tableView.frame.height - InvertedTableView.inset
|
||||
} else { false }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user