120 lines
2.7 KiB
Swift
120 lines
2.7 KiB
Swift
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)
|
|
}
|
|
|
|
}
|