import Foundation import SwiftUI final class FileResource: Item { let type: FileType @Published var isExternallyStored: Bool @Published var german: String @Published var english: String @Published var size: CGSize = .zero init(content: Content, id: String, isExternallyStored: Bool, en: String, de: String) { self.type = FileType(fileExtension: id.fileExtension) self.english = en self.german = de self.isExternallyStored = isExternallyStored super.init(content: content, id: id) } /** Only for bundle images */ init(resourceImage: String, type: ImageFileType) { self.type = .image(type) self.english = "A test image included in the bundle" self.german = "Ein Testbild aus dem Bundle" self.isExternallyStored = true super.init(content: .mock, id: resourceImage) // TODO: Add images to mock } // MARK: Text func textContent() -> String { content.storage.fileContent(for: id) ?? "" } func dataContent() -> Data? { content.storage.fileData(for: id) } // MARK: Images var aspectRatio: CGFloat { guard size.height > 0 else { return 0 } return size.width / size.height } var imageToDisplay: Image { guard let imageData = content.storage.fileData(for: id) else { print("Failed to load data for image \(id)") return failureImage } guard let loadedImage = NSImage(data: imageData) else { print("Failed to create image \(id)") return failureImage } if self.size == .zero && loadedImage.size != .zero { DispatchQueue.main.async { self.size = loadedImage.size } } return .init(nsImage: loadedImage) } private var failureImage: Image { Image(systemSymbol: .exclamationmarkTriangle) } // MARK: Paths /** Get the url path to a file in the output folder. The result is an absolute path from the output folder for use in HTML. */ var absoluteUrl: String { let path = pathPrefix + "/" + id return makeCleanAbsolutePath(path) } var assetUrl: String { let path = content.settings.paths.assetsOutputFolderPath + "/" + id return makeCleanAbsolutePath(path) } private var pathPrefix: String { switch type { case .image: return content.settings.paths.imagesOutputFolderPath case .video: return content.settings.paths.videosOutputFolderPath default: return content.settings.paths.filesOutputFolderPath } } // MARK: File func isValid(id: String) -> Bool { !id.isEmpty && content.isValidIdForFile(id) && content.isNewIdForFile(id) } @discardableResult func update(id newId: String) -> Bool { guard !isExternallyStored else { id = newId return true } guard content.storage.move(file: id, to: newId) else { print("Failed to move file \(id) to \(newId)") return false } id = newId return true } } extension FileResource: LocalizedItem { } extension FileResource: CustomStringConvertible { var description: String { id } }