Tusker/Tusker/CoreData/StatusMO.swift

163 lines
5.7 KiB
Swift

//
// 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<StatusMO> {
return NSFetchRequest<StatusMO>(entityName: "Status")
}
@nonobjc public class func fetchRequest(id: String) -> NSFetchRequest<StatusMO> {
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
}
}
}