81 lines
2.6 KiB
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
|
|
}
|
|
}
|