Tusker/Tusker/Screens/Conversation/ConversationTree.swift

81 lines
2.6 KiB
Swift

//
// ConversationTree.swift
// Tusker
//
// Created by Shadowfacts on 2/4/23.
// Copyright © 2023 Shadowfacts. All rights reserved.
//
import Foundation
import Pachyderm
class ConversationNode {
let status: StatusMO
var children: [ConversationNode]
init(status: StatusMO) {
self.status = status
self.children = []
}
}
struct ConversationTree {
let ancestors: [String]
let descendants: [ConversationNode]
static func build(from context: ConversationContext, mainStatus: StatusMO, descendants: [StatusMO]) -> ConversationTree {
let ancestors = getDirectParents(inReplyTo: mainStatus.inReplyToID, from: context)
let childThreads = getDescendantThreads(mainStatus: mainStatus, descendants: descendants)
return ConversationTree(ancestors: ancestors, descendants: childThreads)
}
private static func getDirectParents(inReplyTo inReplyToID: String?, from context: ConversationContext) -> [String] {
var statuses = context.ancestors
var parents = [String]()
var parentID: String? = inReplyToID
while let currentParentID = parentID,
let parentIndex = statuses.firstIndex(where: { $0.id == currentParentID }) {
let parentStatus = statuses.remove(at: parentIndex)
parents.insert(parentStatus.id, at: 0)
parentID = parentStatus.inReplyToID
}
return parents
}
private static func getDescendantThreads(mainStatus: StatusMO, descendants: [StatusMO]) -> [ConversationNode] {
var descendants = descendants
func removeAllInReplyTo(id: String) -> [StatusMO] {
let statuses = descendants.filter { $0.inReplyToID == id }
descendants.removeAll { $0.inReplyToID == id }
return statuses
}
let mainStatusNode = ConversationNode(status: mainStatus)
var nodes: [String: ConversationNode] = [
mainStatus.id: mainStatusNode
]
var idsToCheck = [mainStatus.id]
while !idsToCheck.isEmpty {
let inReplyToID = idsToCheck.removeFirst()
let nodeForID = nodes[inReplyToID]!
let inReply = removeAllInReplyTo(id: inReplyToID)
for reply in inReply {
idsToCheck.append(reply.id)
let replyNode = ConversationNode(status: reply)
nodes[reply.id] = replyNode
nodeForID.children.append(replyNode)
}
}
return mainStatusNode.children
}
}