// // TimlineState.swift // Tusker // // Created by Shadowfacts on 12/13/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import Foundation import CoreData import Pachyderm @objc(TimelineState) public final class TimelineState: NSManagedObject { @nonobjc public class func fetchRequest(timeline: Timeline) -> NSFetchRequest { let req = NSFetchRequest(entityName: "TimelineState") req.predicate = NSPredicate(format: "timelineKind = %@", toTimelineKind(timeline)) return req } @NSManaged private var timelineKind: String @NSManaged public var centerStatusID: String? @NSManaged private var statuses: NSOrderedSet var timeline: Timeline { get { fromTimelineKind(timelineKind) } set { timelineKind = toTimelineKind(newValue) } } var statusMOs: [StatusMO] { statuses.array as! [StatusMO] } convenience init(timeline: Timeline, context: NSManagedObjectContext) { self.init(context: context) self.timeline = timeline } func setStatuses(_ statusIDs: [String]) { let context = managedObjectContext! // todo: this feels really inefficient, but I'm not sure if it's better or worse than doing a single "id IN %@" fetch and sorting after let mos = statusIDs.compactMap { try? context.fetch(StatusMO.fetchRequest(id: $0)).first } self.statuses = NSOrderedSet(array: mos) } } // blergh, this is the simplest way of getting the Timeline into a format that A) CoreData can handle and B) is usable in the predicate private func toTimelineKind(_ timeline: Timeline) -> String { switch timeline { case .home: return "home" case .public(local: true): return "local" case .public(local: false): return "federated" case .direct: return "direct" case .tag(hashtag: let name): return "hashtag:\(name)" case .list(id: let id): return "list:\(id)" } } private func fromTimelineKind(_ kind: String) -> Timeline { if kind == "home" { return .home } else if kind == "local" { return .public(local: true) } else if kind == "federated" { return .public(local: false) } else if kind == "direct" { return .direct } else if kind.starts(with: "hashtag:") { return .tag(hashtag: String(trimmingPrefix("hashtag:", of: kind))) } else if kind.starts(with: "list:") { return .list(id: String(trimmingPrefix("list:", of: kind))) } else { fatalError("invalid timeline kind \(kind)") } } // replace with Collection.trimmingPrefix @available(iOS, obsoleted: 16.0) private func trimmingPrefix(_ prefix: String, of str: String) -> Substring { return str[str.index(str.startIndex, offsetBy: prefix.count)...] }