// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit import SessionMessagingKit protocol LinkPreviewState { var isLoaded: Bool { get } var urlString: String? { get } var title: String? { get } var imageState: LinkPreview.ImageState { get } var image: UIImage? { get } } public extension LinkPreview { enum ImageState: Int { case none case loading case loaded case invalid } // MARK: LoadingState struct LoadingState: LinkPreviewState { var isLoaded: Bool { false } var urlString: String? { nil } var title: String? { nil } var imageState: LinkPreview.ImageState { .none } var image: UIImage? { nil } } // MARK: DraftState struct DraftState: LinkPreviewState { var isLoaded: Bool { true } var urlString: String? { linkPreviewDraft.urlString } var title: String? { guard let value = linkPreviewDraft.title, value.count > 0 else { return nil } return value } var imageState: LinkPreview.ImageState { if linkPreviewDraft.jpegImageData != nil { return .loaded } return .none } var image: UIImage? { guard let jpegImageData = linkPreviewDraft.jpegImageData else { return nil } guard let image = UIImage(data: jpegImageData) else { owsFailDebug("Could not load image: \(jpegImageData.count)") return nil } return image } // MARK: - Type Specific private let linkPreviewDraft: LinkPreviewDraft // MARK: - Initialization init(linkPreviewDraft: LinkPreviewDraft) { self.linkPreviewDraft = linkPreviewDraft } } // MARK: SentState struct SentState: LinkPreviewState { var isLoaded: Bool { true } var urlString: String? { linkPreview.url } var title: String? { guard let value = linkPreview.title, value.count > 0 else { return nil } return value } var imageState: LinkPreview.ImageState { guard linkPreview.attachmentId != nil else { return .none } guard let imageAttachment: Attachment = imageAttachment else { owsFailDebug("Missing imageAttachment.") return .none } switch imageAttachment.state { case .downloaded, .uploaded: guard imageAttachment.isImage && imageAttachment.isValid else { return .invalid } return .loaded case .pendingDownload, .downloading, .uploading: return .loading case .failedDownload, .failedUpload, .invalid: return .invalid } } var image: UIImage? { // Note: We don't check if the image is valid here because that can be confirmed // in 'imageState' and it's a little inefficient guard imageAttachment?.isImage == true else { return nil } guard let imageData: Data = try? imageAttachment?.readDataFromFile() else { return nil } guard let image = UIImage(data: imageData) else { owsFailDebug("Could not load image: \(imageAttachment?.localRelativeFilePath ?? "unknown")") return nil } return image } // MARK: - Type Specific private let linkPreview: LinkPreview private let imageAttachment: Attachment? public var imageSize: CGSize { guard let width: UInt = imageAttachment?.width, let height: UInt = imageAttachment?.height else { return CGSize.zero } return CGSize(width: CGFloat(width), height: CGFloat(height)) } // MARK: - Initialization init(linkPreview: LinkPreview, imageAttachment: Attachment?) { self.linkPreview = linkPreview self.imageAttachment = imageAttachment } } }