Files
mobile-ios/Rosetta/Features/Chats/ChatDetail/PendingAttachment.swift

92 lines
2.9 KiB
Swift

import UIKit
// MARK: - PendingAttachment
/// Represents an attachment selected by the user but not yet sent.
/// Used in the attachment preview strip above the compositor.
///
/// Desktop parity: the `attachments` state array in `DialogInput.tsx` before
/// `prepareAttachmentsToSend()` processes and uploads them.
struct PendingAttachment: Identifiable, Sendable {
/// Random 8-character alphanumeric ID (matches desktop's `generateRandomKey(8)`).
let id: String
/// Attachment type `.image` or `.file` for user-initiated sends.
let type: AttachmentType
/// Raw image/file data (pre-compression for images).
let data: Data
/// Thumbnail for preview (images only). `nil` for files.
let thumbnail: UIImage?
/// Original file name (files only). `nil` for images.
let fileName: String?
/// File size in bytes (files only). `nil` for images.
let fileSize: Int?
// MARK: - Factory
/// Creates a PendingAttachment from a UIImage (compressed to JPEG).
static func fromImage(_ image: UIImage) -> PendingAttachment {
let id = generateRandomId()
// Resize to max 1280px on longest side for mobile optimization
let resized = resizeImage(image, maxDimension: 1280)
let data = resized.jpegData(compressionQuality: 0.8) ?? Data()
let thumbnail = resizeImage(image, maxDimension: 200)
return PendingAttachment(
id: id,
type: .image,
data: data,
thumbnail: thumbnail,
fileName: nil,
fileSize: nil
)
}
/// Creates a PendingAttachment from file data + metadata.
static func fromFile(data: Data, fileName: String) -> PendingAttachment {
return PendingAttachment(
id: generateRandomId(),
type: .file,
data: data,
thumbnail: nil,
fileName: fileName,
fileSize: data.count
)
}
// MARK: - Helpers
/// Generates a random 8-character ID (desktop: `generateRandomKey(8)`).
private static func generateRandomId() -> String {
let chars = "abcdefghijklmnopqrstuvwxyz0123456789"
return String((0..<8).map { _ in chars.randomElement()! })
}
/// Resizes image so longest side is at most `maxDimension`.
private static func resizeImage(_ image: UIImage, maxDimension: CGFloat) -> UIImage {
let size = image.size
let maxSide = max(size.width, size.height)
guard maxSide > maxDimension else { return image }
let scale = maxDimension / maxSide
let newSize = CGSize(width: size.width * scale, height: size.height * scale)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: newSize))
}
}
}
// MARK: - Constants
extension PendingAttachment {
/// Desktop parity: `MAX_ATTACHMENTS_IN_MESSAGE = 5`.
static let maxAttachmentsPerMessage = 5
}