|  |  |  | // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import Foundation | 
					
						
							|  |  |  | import GRDB | 
					
						
							|  |  |  | import SessionUtilitiesKit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public extension VisibleMessage { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct VMQuote: Codable { | 
					
						
							|  |  |  |         public let timestamp: UInt64? | 
					
						
							|  |  |  |         public let publicKey: String? | 
					
						
							|  |  |  |         public let text: String? | 
					
						
							|  |  |  |         public let attachmentId: String? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public var isValid: Bool { timestamp != nil && publicKey != nil } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // MARK: - Initialization | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         internal init(timestamp: UInt64, publicKey: String, text: String?, attachmentId: String?) { | 
					
						
							|  |  |  |             self.timestamp = timestamp | 
					
						
							|  |  |  |             self.publicKey = publicKey | 
					
						
							|  |  |  |             self.text = text | 
					
						
							|  |  |  |             self.attachmentId = attachmentId | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // MARK: - Proto Conversion | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public static func fromProto(_ proto: SNProtoDataMessageQuote) -> VMQuote? { | 
					
						
							|  |  |  |             return VMQuote( | 
					
						
							|  |  |  |                 timestamp: proto.id, | 
					
						
							|  |  |  |                 publicKey: proto.author, | 
					
						
							|  |  |  |                 text: proto.text, | 
					
						
							|  |  |  |                 attachmentId: nil | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public func toProto() -> SNProtoDataMessageQuote? { | 
					
						
							|  |  |  |             preconditionFailure("Use toProto(_:) instead.") | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public func toProto(_ db: Database) -> SNProtoDataMessageQuote? { | 
					
						
							|  |  |  |             guard let timestamp = timestamp, let publicKey = publicKey else { | 
					
						
							|  |  |  |                 SNLog("Couldn't construct quote proto from: \(self).") | 
					
						
							|  |  |  |                 return nil | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey) | 
					
						
							|  |  |  |             if let text = text { quoteProto.setText(text) } | 
					
						
							|  |  |  |             addAttachmentsIfNeeded(db, to: quoteProto) | 
					
						
							|  |  |  |             do { | 
					
						
							|  |  |  |                 return try quoteProto.build() | 
					
						
							|  |  |  |             } catch { | 
					
						
							|  |  |  |                 SNLog("Couldn't construct quote proto from: \(self).") | 
					
						
							|  |  |  |                 return nil | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         private func addAttachmentsIfNeeded(_ db: Database, to quoteProto: SNProtoDataMessageQuote.SNProtoDataMessageQuoteBuilder) { | 
					
						
							|  |  |  |             guard let attachmentId = attachmentId else { return } | 
					
						
							|  |  |  |             guard | 
					
						
							|  |  |  |                 let attachment: Attachment = try? Attachment.fetchOne(db, id: attachmentId), | 
					
						
							|  |  |  |                 attachment.state == .uploaded | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 #if DEBUG | 
					
						
							|  |  |  |                 preconditionFailure("Sending a message before all associated attachments have been uploaded.") | 
					
						
							|  |  |  |                 #else | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |                 #endif | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             let quotedAttachmentProto = SNProtoDataMessageQuoteQuotedAttachment.builder() | 
					
						
							|  |  |  |             quotedAttachmentProto.setContentType(attachment.contentType) | 
					
						
							|  |  |  |             if let fileName = attachment.sourceFilename { quotedAttachmentProto.setFileName(fileName) } | 
					
						
							|  |  |  |             guard let attachmentProto = attachment.buildProto() else { | 
					
						
							|  |  |  |                 return SNLog("Ignoring invalid attachment for quoted message.") | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             quotedAttachmentProto.setThumbnail(attachmentProto) | 
					
						
							|  |  |  |             do { | 
					
						
							|  |  |  |                 try quoteProto.addAttachments(quotedAttachmentProto.build()) | 
					
						
							|  |  |  |             } catch { | 
					
						
							|  |  |  |                 SNLog("Couldn't construct quoted attachment proto from: \(self).") | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // MARK: - Description | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         public var description: String { | 
					
						
							|  |  |  |             """
 | 
					
						
							|  |  |  |             Quote( | 
					
						
							|  |  |  |                 timestamp: \(timestamp?.description ?? "null"), | 
					
						
							|  |  |  |                 publicKey: \(publicKey ?? "null"), | 
					
						
							|  |  |  |                 text: \(text ?? "null"), | 
					
						
							|  |  |  |                 attachmentId: \(attachmentId ?? "null") | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             """
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MARK: - Database Type Conversion | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public extension VisibleMessage.VMQuote { | 
					
						
							|  |  |  |     static func from(_ db: Database, quote: Quote) -> VisibleMessage.VMQuote { | 
					
						
							|  |  |  |         return VisibleMessage.VMQuote( | 
					
						
							|  |  |  |             timestamp: UInt64(quote.timestampMs), | 
					
						
							|  |  |  |             publicKey: quote.authorId, | 
					
						
							|  |  |  |             text: quote.body, | 
					
						
							|  |  |  |             attachmentId: quote.attachmentId | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |