From aae3bd0bbab2be0868be458a557c23adf457b2c4 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 2 Nov 2023 17:53:26 -0400 Subject: [PATCH] Remove dead code --- .../Sources/ComposeUI/API/PostService.swift | 4 +- .../ComposeUI/Model/AttachmentData.swift | 278 ------------------ 2 files changed, 2 insertions(+), 280 deletions(-) delete mode 100644 Packages/ComposeUI/Sources/ComposeUI/Model/AttachmentData.swift diff --git a/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift b/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift index 2097647e..6733c17d 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/API/PostService.swift @@ -111,7 +111,7 @@ class PostService: ObservableObject { do { (data, utType) = try await getData(for: attachment) currentStep += 1 - } catch let error as AttachmentData.Error { + } catch let error as DraftAttachment.ExportError { throw Error.attachmentData(index: index, cause: error) } do { @@ -169,7 +169,7 @@ class PostService: ObservableObject { } enum Error: Swift.Error, LocalizedError { - case attachmentData(index: Int, cause: AttachmentData.Error) + case attachmentData(index: Int, cause: DraftAttachment.ExportError) case attachmentUpload(index: Int, cause: Client.Error) case posting(Client.Error) diff --git a/Packages/ComposeUI/Sources/ComposeUI/Model/AttachmentData.swift b/Packages/ComposeUI/Sources/ComposeUI/Model/AttachmentData.swift deleted file mode 100644 index 7bd31cd2..00000000 --- a/Packages/ComposeUI/Sources/ComposeUI/Model/AttachmentData.swift +++ /dev/null @@ -1,278 +0,0 @@ -// -// AttachmentData.swift -// ComposeUI -// -// Created by Shadowfacts on 1/1/20. -// Copyright © 2020 Shadowfacts. All rights reserved. -// - -import UIKit -import Photos -import UniformTypeIdentifiers -import PencilKit -import InstanceFeatures - -enum AttachmentData { - case asset(PHAsset) - case image(Data, originalType: UTType) - case video(URL) - case drawing(PKDrawing) - case gif(Data) - - var type: AttachmentType { - switch self { - case let .asset(asset): - return asset.attachmentType! - case .image(_, originalType: _): - return .image - case .video(_): - return .video - case .drawing(_): - return .image - case .gif(_): - return .image - } - } - - var isAsset: Bool { - switch self { - case .asset(_): - return true - default: - return false - } - } - - var canSaveToDraft: Bool { - switch self { - case .video(_): - return false - default: - return true - } - } - - func getData(features: InstanceFeatures, skipAllConversion: Bool = false, completion: @escaping (Result<(Data, UTType), Error>) -> Void) { - switch self { - case let .image(originalData, originalType): - let data: Data - let type: UTType - switch originalType { - case .png, .jpeg: - data = originalData - type = originalType - default: - let image = UIImage(data: originalData)! - // The quality of 0.8 was chosen completely arbitrarily, it may need to be tuned in the future. - data = image.jpegData(compressionQuality: 0.8)! - type = .jpeg - } - let processed = processImageData(data, type: type, features: features, skipAllConversion: skipAllConversion) - completion(.success(processed)) - case let .asset(asset): - if asset.mediaType == .image { - let options = PHImageRequestOptions() - options.version = .current - options.deliveryMode = .highQualityFormat - options.resizeMode = .none - options.isNetworkAccessAllowed = true - PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { (data, dataUTI, orientation, info) in - guard let data = data, let dataUTI = dataUTI else { - completion(.failure(.missingData)) - return - } - let processed = processImageData(data, type: UTType(dataUTI)!, features: features, skipAllConversion: skipAllConversion) - completion(.success(processed)) - } - } else if asset.mediaType == .video { - let options = PHVideoRequestOptions() - options.deliveryMode = .automatic - options.isNetworkAccessAllowed = true - options.version = .current - PHImageManager.default().requestExportSession(forVideo: asset, options: options, exportPreset: AVAssetExportPresetHighestQuality) { (exportSession, info) in - if let exportSession = exportSession { - AttachmentData.exportVideoData(session: exportSession, completion: completion) - } else if let error = info?[PHImageErrorKey] as? Error { - completion(.failure(.videoExport(error))) - } else { - completion(.failure(.noVideoExportSession)) - } - } - } else { - fatalError("assetType must be either image or video") - } - case let .video(url): - let asset = AVURLAsset(url: url) - guard let session = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else { - completion(.failure(.noVideoExportSession)) - return - } - AttachmentData.exportVideoData(session: session, completion: completion) - - case let .drawing(drawing): - let image = drawing.imageInLightMode(from: drawing.bounds, scale: 1) - completion(.success((image.pngData()!, .png))) - case let .gif(data): - completion(.success((data, .gif))) - } - } - - private func processImageData(_ data: Data, type: UTType, features: InstanceFeatures, skipAllConversion: Bool) -> (Data, UTType) { - guard !skipAllConversion else { - return (data, type) - } - - var data = data - var type = type - let image = CIImage(data: data)! - let needsColorSpaceConversion = features.needsWideColorGamutHack && image.colorSpace?.name != CGColorSpace.sRGB - - // neither Mastodon nor Pleroma handles HEIC well, so convert to JPEG - // they also do a bad job converting wide color gamut images (they seem to just drop the profile, letting the wide-gamut values be reinterprete as sRGB) - // if that changes in the future, we'll need to pass the InstanceFeatures in here somehow and gate the conversion - if needsColorSpaceConversion || type == .heic { - let context = CIContext() - let colorSpace = needsColorSpaceConversion || image.colorSpace != nil ? CGColorSpace(name: CGColorSpace.sRGB)! : image.colorSpace! - if type == .png { - data = context.pngRepresentation(of: image, format: .ARGB8, colorSpace: colorSpace)! - } else { - data = context.jpegRepresentation(of: image, colorSpace: colorSpace)! - type = .jpeg - } - } - - return (data, type) - } - - private static func exportVideoData(session: AVAssetExportSession, completion: @escaping (Result<(Data, UTType), Error>) -> Void) { - session.outputFileType = .mp4 - session.outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("exported_video_\(UUID())").appendingPathExtension("mp4") - session.exportAsynchronously { - guard session.status == .completed else { - completion(.failure(.videoExport(session.error!))) - return - } - do { - let data = try Data(contentsOf: session.outputURL!) - completion(.success((data, .mpeg4Movie))) - } catch { - completion(.failure(.videoExport(error))) - } - } - } - - enum AttachmentType { - case image, video - } - - enum Error: Swift.Error, LocalizedError { - case missingData - case videoExport(Swift.Error) - case noVideoExportSession - - var localizedDescription: String { - switch self { - case .missingData: - return "Missing Data" - case .videoExport(let error): - return "Exporting video: \(error)" - case .noVideoExportSession: - return "Couldn't create video export session" - } - } - } -} - -extension PHAsset { - var attachmentType: AttachmentData.AttachmentType? { - switch self.mediaType { - case .image: - return .image - case .video: - return .video - default: - return nil - } - } -} - -extension AttachmentData: Codable { - func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - switch self { - case let .asset(asset): - try container.encode("asset", forKey: .type) - try container.encode(asset.localIdentifier, forKey: .assetIdentifier) - case let .image(originalData, originalType): - try container.encode("image", forKey: .type) - try container.encode(originalType, forKey: .imageType) - try container.encode(originalData, forKey: .imageData) - case .video(_): - throw EncodingError.invalidValue(self, EncodingError.Context(codingPath: encoder.codingPath, debugDescription: "video CompositionAttachments cannot be encoded")) - case let .drawing(drawing): - try container.encode("drawing", forKey: .type) - let drawingData = drawing.dataRepresentation() - try container.encode(drawingData, forKey: .drawing) - case .gif(_): - throw EncodingError.invalidValue(self, EncodingError.Context(codingPath: encoder.codingPath, debugDescription: "gif CompositionAttachments cannot be encoded")) - } - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - switch try container.decode(String.self, forKey: .type) { - case "asset": - let identifier = try container.decode(String.self, forKey: .assetIdentifier) - guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject else { - throw DecodingError.dataCorruptedError(forKey: .assetIdentifier, in: container, debugDescription: "Could not fetch asset with local identifier") - } - self = .asset(asset) - case "image": - let data = try container.decode(Data.self, forKey: .imageData) - if let type = try container.decodeIfPresent(UTType.self, forKey: .imageType) { - self = .image(data, originalType: type) - } else { - guard let image = UIImage(data: data) else { - throw DecodingError.dataCorruptedError(forKey: .imageData, in: container, debugDescription: "CompositionAttachment data could not be decoded into UIImage") - } - let jpegData = image.jpegData(compressionQuality: 1)! - self = .image(jpegData, originalType: .jpeg) - } - case "drawing": - let drawingData = try container.decode(Data.self, forKey: .drawing) - let drawing = try PKDrawing(data: drawingData) - self = .drawing(drawing) - default: - throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "CompositionAttachment type must be one of image, asset, or drawing") - } - } - - enum CodingKeys: CodingKey { - case type - case imageData - case imageType - /// The local identifier of the PHAsset for this attachment - case assetIdentifier - /// The PKDrawing object for this attachment. - case drawing - } -} - -extension AttachmentData: Equatable { - static func ==(lhs: AttachmentData, rhs: AttachmentData) -> Bool { - switch (lhs, rhs) { - case let (.asset(a), .asset(b)): - return a.localIdentifier == b.localIdentifier - case let (.image(a, originalType: aType), .image(b, originalType: bType)): - return a == b && aType == bType - case let (.video(a), .video(b)): - return a == b - case let (.drawing(a), .drawing(b)): - return a == b - default: - return false - } - } -}