import SwiftUI final class ImageResource: ObservableObject { @Published var type: ImageType /// Globally unique id @Published var id: String @Published var germanDescription: String @Published var englishDescription: String @Published var size: CGSize = .zero var aspectRatio: CGFloat { guard size.height > 0 else { return 0 } return size.width / size.height } private let source: ImageSource init(type: ImageType, uniqueId: String, en: String, de: String, fileUrl: URL) { self.type = type self.id = uniqueId self.source = .file(fileUrl) self.englishDescription = en self.germanDescription = de } init(resourceName: String, type: ImageType) { self.type = type self.id = resourceName self.source = .resource(resourceName) self.englishDescription = "A test image included in the bundle" self.germanDescription = "Ein Test-Image aus dem Bundle" } private enum ImageSource { case file(URL) case resource(String) } func getDescription(for language: ContentLanguage) -> String { switch language { case .english: return englishDescription case .german: return germanDescription } } } extension ImageResource: Identifiable { } extension ImageResource: Comparable { static func < (lhs: ImageResource, rhs: ImageResource) -> Bool { lhs.id < rhs.id } } extension ImageResource: Equatable { static func == (lhs: ImageResource, rhs: ImageResource) -> Bool { lhs.id == rhs.id } } extension ImageResource: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(id) } } extension ImageResource { var imageToDisplay: Image { switch source { case .file(let url): return image(at: url) case .resource(let name): return .init(name) } } private func image(at url: URL) -> Image { let imageData: Data do { imageData = try Data(contentsOf: url) } catch { print("Failed to load image data from \(url.path): \(error)") return failureImage } guard let loadedImage = NSImage(data: imageData) else { print("Failed to create image from \(url.path)") return failureImage } if self.size == .zero && loadedImage.size != .zero { DispatchQueue.main.async { self.size = loadedImage.size } } return .init(nsImage: loadedImage) } private var failureImage: SwiftUI.Image { Image(systemSymbol: .exclamationmarkTriangle) } }