// // StatusMO.swift // Tusker // // Created by Shadowfacts on 4/11/20. // Copyright © 2020 Shadowfacts. All rights reserved. // // import Foundation import CoreData import Pachyderm import WebURLFoundationExtras @objc(StatusMO) public final class StatusMO: NSManagedObject, StatusProtocol { @nonobjc public class func fetchRequest() -> NSFetchRequest { return NSFetchRequest(entityName: "Status") } @nonobjc public class func fetchRequest(id: String) -> NSFetchRequest { let req = Self.fetchRequest() req.predicate = NSPredicate(format: "id = %@", id) return req } @NSManaged public var applicationName: String? @NSManaged private var attachmentsData: Data? @NSManaged private var bookmarkedInternal: Bool @NSManaged public var cardData: Data? @NSManaged public var content: String @NSManaged public var createdAt: Date @NSManaged public var editedAt: Date? @NSManaged private var emojisData: Data? @NSManaged public var favourited: Bool @NSManaged public var favouritesCount: Int @NSManaged private var hashtagsData: Data? @NSManaged public var id: String @NSManaged public var inReplyToAccountID: String? @NSManaged public var inReplyToID: String? @NSManaged private var mentionsData: Data? @NSManaged public var muted: Bool @NSManaged private var pinnedInternal: Bool @NSManaged public var reblogged: Bool @NSManaged public var reblogsCount: Int @NSManaged public var sensitive: Bool @NSManaged public var spoilerText: String @NSManaged public var uri: String // todo: are both uri and url necessary? @NSManaged public var url: URL? @NSManaged private var visibilityString: String @NSManaged private var pollData: Data? @NSManaged public var account: AccountMO @NSManaged public var reblog: StatusMO? @NSManaged public var localOnly: Bool @NSManaged public var lastFetchedAt: Date? @NSManaged public var language: String? @LazilyDecoding(arrayFrom: \StatusMO.attachmentsData) public var attachments: [Attachment] @LazilyDecoding(arrayFrom: \StatusMO.emojisData) public var emojis: [Emoji] @LazilyDecoding(arrayFrom: \StatusMO.hashtagsData) public var hashtags: [Hashtag] @LazilyDecoding(arrayFrom: \StatusMO.mentionsData) public var mentions: [Mention] @LazilyDecoding(from: \StatusMO.cardData, fallback: nil) public var card: Card? @LazilyDecoding(from: \StatusMO.pollData, fallback: nil) public var poll: Poll? public var pinned: Bool? { pinnedInternal } public var bookmarked: Bool? { bookmarkedInternal } public var visibility: Pachyderm.Visibility { get { Pachyderm.Visibility(rawValue: visibilityString) ?? .public } set { visibilityString = newValue.rawValue } } public override func awakeFromFetch() { super.awakeFromFetch() managedObjectContext?.perform { self.touch() } } /// Update the `lastFetchedAt` date so this object isn't pruned early. func touch() { lastFetchedAt = Date() } } extension StatusMO { convenience init(apiStatus status: Pachyderm.Status, container: MastodonCachePersistentStore, context: NSManagedObjectContext) { self.init(context: context) self.updateFrom(apiStatus: status, container: container) self.lastFetchedAt = Date() } func updateFrom(apiStatus status: Pachyderm.Status, container: MastodonCachePersistentStore) { guard let context = managedObjectContext else { // we have been deleted, don't bother updating return } self.applicationName = status.application?.name self.attachments = status.attachments self.bookmarkedInternal = status.bookmarked ?? false self.card = status.card self.content = status.content self.createdAt = status.createdAt self.editedAt = status.editedAt self.emojis = status.emojis self.favourited = status.favourited ?? false self.favouritesCount = status.favouritesCount self.hashtags = status.hashtags self.inReplyToAccountID = status.inReplyToAccountID self.inReplyToID = status.inReplyToID self.id = status.id self.mentions = status.mentions self.muted = status.muted ?? false self.pinnedInternal = status.pinned ?? false self.reblogged = status.reblogged ?? false self.reblogsCount = status.reblogsCount self.sensitive = status.sensitive self.spoilerText = status.spoilerText self.uri = status.uri self.url = status.url != nil ? URL(status.url!) : nil self.visibility = status.visibility self.poll = status.poll self.localOnly = status.localOnly ?? false self.language = status.language if let existing = container.account(for: status.account.id, in: context) { existing.updateFrom(apiAccount: status.account, container: container) self.account = existing } else { self.account = AccountMO(apiAccount: status.account, container: container, context: context) } if let reblog = status.reblog { if let existing = container.status(for: reblog.id, in: context) { existing.updateFrom(apiStatus: reblog, container: container) self.reblog = existing } else { self.reblog = StatusMO(apiStatus: reblog, container: container, context: context) } } else { self.reblog = nil } } }