section poping

This commit is contained in:
Diogo
2024-10-21 16:57:44 +01:00
parent d21dc77566
commit 37ba244e04
2 changed files with 99 additions and 15 deletions
+3 -12
View File
@@ -13,11 +13,6 @@ import Combine
private let memberImageSize: CGFloat = 34
struct PaginationBoundary {
var oldest: Bool
var latest: Bool
}
struct ChatView: View {
@EnvironmentObject var chatModel: ChatModel
@ObservedObject var im = ItemsModel.shared
@@ -37,7 +32,6 @@ struct ChatView: View {
@State private var customUserProfile: Profile?
@State private var connectionCode: String?
@State private var loadingItems = false
@State private var paginationBoundary = PaginationBoundary(oldest: false, latest: false)
@State private var revealedChatItem: ChatItem?
@State private var searchMode = false
@State private var searchText: String = ""
@@ -171,10 +165,6 @@ struct ChatView: View {
selectedChatItems = nil
initChatView()
}
.onChange(of: sectionModel.activeSection) { ac in
paginationBoundary.oldest = false
paginationBoundary.latest = false
}
.onChange(of: chatModel.chatId) { cId in
showChatInfoSheet = false
selectedChatItems = nil
@@ -868,11 +858,11 @@ struct ChatView: View {
}
private func boundaryReached(_ direction: ChatScrollDirection) -> Bool {
return (direction == .toLatest && paginationBoundary.latest) || (direction == .toOldest && paginationBoundary.oldest)
return (direction == .toLatest && sectionModel.boundaries.latest) || (direction == .toOldest && sectionModel.boundaries.oldest)
}
private func setBoundary(_ direction: ChatScrollDirection) {
direction == .toLatest ? (paginationBoundary.latest = true) : (paginationBoundary.oldest = true)
direction == .toLatest ? (sectionModel.boundaries.latest = true) : (sectionModel.boundaries.oldest = true)
}
private func loadChatItems(_ cInfo: ChatInfo, _ direction: ChatScrollDirection, _ section: ChatSection, _ chatItem: ChatItem?) {
@@ -902,6 +892,7 @@ struct ChatView: View {
chatItemsAvailable = !chatItems.isEmpty
reversedPage.append(contentsOf: chatItems.reversed())
}
await MainActor.run {
if reversedPage.count == 0 {
setBoundary(direction)
+96 -3
View File
@@ -101,6 +101,13 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
let firstItem = self.getFirstItemInItemSection(indexPath: indexPath)
self.representer.loadPage(.toLatest, section, firstItem)
}
if (self.scrollDirection == .toOldest && indexPath.item - ReverseListSectionModel.IDEAL_SECTION_SIZE > 8) ||
(self.scrollDirection == .toLatest && indexPath.item < ReverseListSectionModel.IDEAL_SECTION_SIZE) {
Task {
self.representer.sectionModel.manageActiveSection(scrollDirection: self.scrollDirection)
}
}
}
}
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseId, for: indexPath)
@@ -200,8 +207,10 @@ struct ReverseList<Content: View>: UIViewControllerRepresentable {
func scroll(to index: Int?, position: UITableView.ScrollPosition, section: ChatSection, shouldTryAnimate: Bool) {
let activeSectionBeforeScroll = representer.sectionModel.activeSection
Task {
representer.sectionModel.activeSection = section
if section != activeSectionBeforeScroll {
Task {
representer.sectionModel.changeActiveSection(section)
}
}
var animated = false
if #available(iOS 16.0, *) {
@@ -410,10 +419,18 @@ class ReverseListScrollModel: ObservableObject {
}
}
struct SectionBoundaryReached {
var oldest: Bool
var latest: Bool
}
/// Manages ``ReverseList`` sections
class ReverseListSectionModel: ObservableObject {
static let shared = ReverseListSectionModel()
@Published var activeSection: ChatSection = .bottom
static let MAX_SECTION_SIZE = 50
static let IDEAL_SECTION_SIZE = 35
@Published private(set) var activeSection: ChatSection = .bottom
@Published var boundaries = SectionBoundaryReached(oldest: false, latest: false)
@Published private var itemSection: [Int64: ChatSection] = [:]
@Published private var sections = Set<ChatSection>()
@@ -421,6 +438,12 @@ class ReverseListSectionModel: ObservableObject {
return itemSection[id]
}
func changeActiveSection(_ section: ChatSection) {
activeSection = section
boundaries.latest = false
boundaries.oldest = false
}
func maybeDropSection(_ section: ChatSection) {
if section == .bottom { return }
let im = ItemsModel.shared
@@ -429,6 +452,76 @@ class ReverseListSectionModel: ObservableObject {
im.reversedChatItems = im.reversedChatItems.filter { it in itemSection[it.id] != section }
}
private func activeSectionItemsCount() -> Int {
// TODO: check
return itemSection.values.filter { $0 == self.activeSection }.count
}
private func trimSection(scrollDirection: ChatScrollDirection, section: ChatSection) {
let im = ItemsModel.shared
var i = scrollDirection == .toLatest ? 0 : im.reversedChatItems.count - 1
let moveToNextIndex: () -> Bool = {
if scrollDirection == .toLatest {
if i < im.reversedChatItems.count - 1 {
i += 1
return false
} else {
return true
}
} else {
if i > 0 {
i -= 1
return false
} else {
return true
}
}
}
var sectionCount = 0
var completed = false
var toRemoveIndexes = IndexSet()
while (!completed) {
let it = im.reversedChatItems[i]
if itemSection[it.id] == section {
if sectionCount >= ReverseListSectionModel.IDEAL_SECTION_SIZE {
toRemoveIndexes.insert(i)
itemSection.removeValue(forKey: it.id)
} else {
sectionCount += 1
}
}
completed = moveToNextIndex()
}
if (!toRemoveIndexes.isEmpty) {
im.reversedChatItems.remove(atOffsets: toRemoveIndexes)
}
}
func manageActiveSection(scrollDirection: ChatScrollDirection) {
let activeSectionCount = activeSectionItemsCount()
switch self.activeSection {
case .bottom:
if scrollDirection == .toLatest, activeSectionCount > ReverseListSectionModel.MAX_SECTION_SIZE {
// boundaries?, the visible item needs to not be there
boundaries.oldest = false
self.trimSection(scrollDirection: scrollDirection, section: self.activeSection)
}
break;
default:
if activeSectionCount > ReverseListSectionModel.MAX_SECTION_SIZE {
if scrollDirection == .toLatest {
boundaries.oldest = false
} else {
boundaries.latest = false
}
self.trimSection(scrollDirection: scrollDirection, section: self.activeSection)
}
}
}
func getSectionsOrdered() -> [ChatSection] {
var orderedSections: [ChatSection] = [.bottom]