gap -> anchor

This commit is contained in:
Diogo
2024-11-11 17:30:48 +00:00
parent b078d62921
commit aa65c197f3
3 changed files with 38 additions and 30 deletions
+9 -9
View File
@@ -43,20 +43,20 @@ private func addTermItem(_ items: inout [TerminalItem], _ item: TerminalItem) {
items.append(item)
}
/// Represents a gap in a list of chat items, indicating where data is missing and should be loaded.
/// Represents an anchor in a list of chat items, indicating where data is missing and should be loaded.
///
/// - Parameters:
/// - itemId: The unique identifier of the last item in the loaded list before the gap.
/// - itemId: The unique identifier of the last item in the loaded list before the anchor.
/// This ID corresponds to an item in the chat history, ordered from older to newer items.
/// It is typically used when loading items via .around or .initial pagination when loading items
/// - indexRange: The range of indexes within `reversedChatItems` array that
/// represents the gap. The first index in this range is the position of the gap itself.
/// For instance, if the array `[0, 1, 2, -100-, 101]` has a gap at index 3, `indexRange`
/// would be `3..<5`, indicating the gap starts at index 3.
/// represents the anchor. The first index in this range is the position of the anchor itself.
/// For instance, if the array `[0, 1, 2, -100-, 101]` has an anchor at index 3, `indexRange`
/// would be `3..<5`, indicating the anchor starts at index 3.
/// - indexRangeInParentItems: The range of indexes in the `ReverseList` or parent UI component
/// that considers revealed or hidden items, showing where the gap appears in the visible list.
/// The first index in this range points to where the gap starts in the UI.
struct ChatGap {
/// that considers revealed or hidden items, showing where the anchor appears in the visible list.
/// The first index in this range points to where the anchor starts in the UI.
struct AnchoredRange {
let itemId: Int64
let indexRange: Range<Int>
let indexRangeInParentItems: Range<Int>
@@ -82,7 +82,7 @@ class ItemsModel: ObservableObject {
// this will cause reversedChatItems to be rendered without throttling
@Published var isLoading = false
@Published var showLoadingProgress = false
@State var gaps: [ChatItem.ID] = []
@State var anchors: [ChatItem.ID] = []
init() {
publisher
+21 -21
View File
@@ -911,7 +911,7 @@ struct ChatView: View {
if !duplicateFound {
if let existingItem = im.reversedChatItems.first {
im.gaps = [existingItem.id]
im.anchors = [existingItem.id]
}
}
@@ -922,7 +922,7 @@ struct ChatView: View {
case .initial:
await MainActor.run {
im.reversedChatItems = chatItems.reversed()
im.gaps = []
im.anchors = []
loadingItems = false
}
case let .after(chatItemId, _):
@@ -932,22 +932,22 @@ struct ChatView: View {
let wasSize = newItems.count
let newItemIds = Set(chatItems.map { $0.id })
let indexInGaps = im.gaps.firstIndex { $0 == chatItemId }
var gapsAfterChatItem: [Int64] = []
if let indexInGaps = indexInGaps, indexInGaps + 1 <= im.gaps.count {
gapsAfterChatItem = Array(im.gaps[indexInGaps + 1..<im.gaps.count])
let indexInAnchors = im.anchors.firstIndex { $0 == chatItemId }
var anchorAfterChatItem: [Int64] = []
if let indexInAnchors = indexInAnchors, indexInAnchors + 1 <= im.anchors.count {
anchorAfterChatItem = Array(im.anchors[indexInAnchors + 1..<im.anchors.count])
}
var gapsToRemove = Set<Int64>()
var anchorsToRemove = Set<Int64>()
var reachedBottom: Bool = false
newItems.removeAll { item in
let isDuplicate = newItemIds.contains(item.id)
if indexInGaps != nil && newItemIds.contains(item.id) {
if gapsAfterChatItem.contains(item.id) {
gapsAfterChatItem.removeAll { $0 == item.id }
gapsToRemove.insert(item.id)
} else if reachedBottom == false && gapsAfterChatItem.isEmpty {
// We passed all gaps and found a duplicated item below all of them, indicating no more gaps below the loaded items.
if indexInAnchors != nil && newItemIds.contains(item.id) {
if anchorAfterChatItem.contains(item.id) {
anchorAfterChatItem.removeAll { $0 == item.id }
anchorsToRemove.insert(item.id)
} else if reachedBottom == false && anchorAfterChatItem.isEmpty {
// We passed all anchors and found a duplicated item below all of them, indicating no more anchors below the loaded items.
reachedBottom = true
}
}
@@ -959,18 +959,18 @@ struct ChatView: View {
await MainActor.run {
im.reversedChatItems = newItems
var newGaps = im.gaps.filter { !gapsToRemove.contains($0) }
var newAnchors = im.anchors.filter { !anchorsToRemove.contains($0) }
if reachedBottom {
newGaps = []
newAnchors = []
} else {
if let enlargedGapIndex = im.gaps.firstIndex(where: { $0 == chatItemId }) {
// Move the gap to the end of the loaded items.
newGaps[enlargedGapIndex] = chatItems.last?.id ?? newGaps[enlargedGapIndex]
if let enlargedAnchorIndex = im.anchors.firstIndex(where: { $0 == chatItemId }) {
// Move the anchor to the end of the loaded items.
newAnchors[enlargedAnchorIndex] = chatItems.last?.id ?? newAnchors[enlargedAnchorIndex]
}
}
im.gaps = newGaps
im.anchors = newAnchors
loadingItems = false
}
case let .before(chatItemId, _):
@@ -984,7 +984,7 @@ struct ChatView: View {
await MainActor.run {
im.reversedChatItems = newItems
im.gaps = im.gaps.filter { !newItemIds.contains($0) }
im.anchors = im.anchors.filter { !newItemIds.contains($0) }
loadingItems = false
}
case .around(_, _):
@@ -995,7 +995,7 @@ struct ChatView: View {
await MainActor.run {
im.reversedChatItems = newItems
if let lastItemId = chatItems.last?.id {
im.gaps.insert(lastItemId, at: 0)
im.anchors.insert(lastItemId, at: 0)
}
loadingItems = false
}
@@ -381,6 +381,14 @@ fun ComposeView(
suspend fun send(chat: Chat, mc: MsgContent, quoted: Long?, file: CryptoFile? = null, live: Boolean = false, ttl: Int?): ChatItem? {
val cInfo = chat.chatInfo
// val composedMessages = Array(300) { index ->
// ComposedMessage(
// file,
// quoted,
// MsgContent.MCText("$index")
// )
// }.toList()
val chatItems = if (chat.chatInfo.chatType == ChatType.Local)
chatModel.controller.apiCreateChatItems(
rh = chat.remoteHostId,