// // Draft.swift // ComposeUI // // Created by Shadowfacts on 8/18/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import Foundation import Combine import Pachyderm public class Draft: Codable, Identifiable, ObservableObject { public let id: UUID var lastModified: Date @Published public var accountID: String @Published public var text: String @Published public var contentWarningEnabled: Bool @Published public var contentWarning: String @Published public var attachments: [DraftAttachment] @Published public var inReplyToID: String? @Published public var visibility: Visibility @Published public var poll: Poll? @Published public var localOnly: Bool var initialText: String public var hasContent: Bool { (!text.isEmpty && text != initialText) || (contentWarningEnabled && !contentWarning.isEmpty) || attachments.count > 0 || poll?.hasContent == true } public init( accountID: String, text: String, contentWarning: String, inReplyToID: String?, visibility: Visibility, localOnly: Bool ) { self.id = UUID() self.lastModified = Date() self.accountID = accountID self.text = text self.contentWarning = contentWarning self.contentWarningEnabled = !contentWarning.isEmpty self.attachments = [] self.inReplyToID = inReplyToID self.visibility = visibility self.localOnly = localOnly self.initialText = text } public required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decode(UUID.self, forKey: .id) self.lastModified = try container.decode(Date.self, forKey: .lastModified) self.accountID = try container.decode(String.self, forKey: .accountID) self.text = try container.decode(String.self, forKey: .text) self.contentWarningEnabled = try container.decode(Bool.self, forKey: .contentWarningEnabled) self.contentWarning = try container.decode(String.self, forKey: .contentWarning) self.attachments = try container.decode([DraftAttachment].self, forKey: .attachments) self.inReplyToID = try container.decode(String?.self, forKey: .inReplyToID) self.visibility = try container.decode(Visibility.self, forKey: .visibility) self.poll = try container.decode(Poll?.self, forKey: .poll) self.localOnly = try container.decodeIfPresent(Bool.self, forKey: .localOnly) ?? false self.initialText = try container.decode(String.self, forKey: .initialText) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(lastModified, forKey: .lastModified) try container.encode(accountID, forKey: .accountID) try container.encode(text, forKey: .text) try container.encode(contentWarningEnabled, forKey: .contentWarningEnabled) try container.encode(contentWarning, forKey: .contentWarning) try container.encode(attachments, forKey: .attachments) try container.encode(inReplyToID, forKey: .inReplyToID) try container.encode(visibility, forKey: .visibility) try container.encode(poll, forKey: .poll) try container.encode(localOnly, forKey: .localOnly) try container.encode(initialText, forKey: .initialText) } } extension Draft: Equatable { public static func ==(lhs: Draft, rhs: Draft) -> Bool { return lhs.id == rhs.id } } extension Draft { enum CodingKeys: String, CodingKey { case id case lastModified case accountID case text case contentWarningEnabled case contentWarning case attachments case inReplyToID case visibility case poll case localOnly case initialText } } extension Draft { public class Poll: Codable, ObservableObject { @Published public var options: [Option] @Published public var multiple: Bool @Published public var duration: TimeInterval var hasContent: Bool { options.contains { !$0.text.isEmpty } } public init() { self.options = [Option(""), Option("")] self.multiple = false self.duration = 24 * 60 * 60 // 1 day } public required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.options = try container.decode([Option].self, forKey: .options) self.multiple = try container.decode(Bool.self, forKey: .multiple) self.duration = try container.decode(TimeInterval.self, forKey: .duration) } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(options, forKey: .options) try container.encode(multiple, forKey: .multiple) try container.encode(duration, forKey: .duration) } private enum CodingKeys: String, CodingKey { case options case multiple case duration } public class Option: Identifiable, Codable, ObservableObject { public let id = UUID() @Published public var text: String init(_ text: String) { self.text = text } public required init(from decoder: Decoder) throws { self.text = try decoder.singleValueContainer().decode(String.self) } public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(text) } } } }