// // TimelinePosition.swift // Tusker // // Created by Shadowfacts on 12/23/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import Foundation import CoreData import Pachyderm import UserAccounts @objc(TimelinePosition) public final class TimelinePosition: NSManagedObject { @nonobjc class func fetchRequest(timeline: Timeline, account: UserAccountInfo) -> NSFetchRequest { let req = NSFetchRequest(entityName: "TimelinePosition") req.predicate = NSPredicate(format: "accountID = %@ AND timelineKind = %@", account.id, toTimelineKind(timeline)) req.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: true)] return req } @NSManaged public var accountID: String @NSManaged public var createdAt: Date @NSManaged private var timelineKind: String @NSManaged public var centerStatusID: String? @NSManaged private var statusIDsData: Data? @LazilyDecoding(arrayFrom: \TimelinePosition.statusIDsData) var statusIDs: [String] var timeline: Timeline { get { fromTimelineKind(timelineKind) } set { timelineKind = toTimelineKind(newValue) } } convenience init(timeline: Timeline, account: UserAccountInfo, context: NSManagedObjectContext) { self.init(context: context) self.timeline = timeline self.accountID = account.id self.createdAt = Date() } func changedRemotely() { _statusIDs.removeCachedValue() } } // 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 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)" } } 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) @available(visionOS 1.0, *) private func trimmingPrefix(_ prefix: String, of str: String) -> Substring { return str[str.index(str.startIndex, offsetBy: prefix.count)...] }