145 lines
3.5 KiB
Swift
145 lines
3.5 KiB
Swift
import Foundation
|
|
import SwiftUI
|
|
|
|
final class FileResource: Item {
|
|
|
|
let type: FileType
|
|
|
|
/// Globally unique id
|
|
@Published
|
|
var id: String
|
|
|
|
@Published
|
|
var isExternallyStored: Bool
|
|
|
|
@Published
|
|
var germanDescription: String
|
|
|
|
@Published
|
|
var englishDescription: String
|
|
|
|
@Published
|
|
var size: CGSize = .zero
|
|
|
|
init(content: Content, id: String, isExternallyStored: Bool, en: String, de: String) {
|
|
self.id = id
|
|
self.type = FileType(fileExtension: id.fileExtension)
|
|
self.englishDescription = en
|
|
self.germanDescription = de
|
|
self.isExternallyStored = isExternallyStored
|
|
super.init(content: content)
|
|
}
|
|
|
|
/**
|
|
Only for bundle images
|
|
*/
|
|
init(resourceImage: String, type: ImageFileType) {
|
|
self.type = .image(type)
|
|
self.id = resourceImage
|
|
self.englishDescription = "A test image included in the bundle"
|
|
self.germanDescription = "Ein Testbild aus dem Bundle"
|
|
self.isExternallyStored = true
|
|
super.init(content: .mock) // TODO: Add images to mock
|
|
}
|
|
|
|
func getDescription(for language: ContentLanguage) -> String {
|
|
switch language {
|
|
case .english: return englishDescription
|
|
case .german: return germanDescription
|
|
}
|
|
}
|
|
|
|
// MARK: Text
|
|
|
|
func textContent() -> String {
|
|
do {
|
|
return try content.storage.fileContent(for: id)
|
|
} catch {
|
|
print("Failed to load text of file \(id): \(error)")
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func dataContent() throws -> Data {
|
|
try 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 {
|
|
let imageData: Data
|
|
do {
|
|
imageData = try content.storage.fileData(for: id)
|
|
} catch {
|
|
print("Failed to load data for image \(id): \(error)")
|
|
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)
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
extension FileResource: Identifiable {
|
|
|
|
}
|
|
|
|
extension FileResource: Equatable {
|
|
|
|
static func == (lhs: FileResource, rhs: FileResource) -> Bool {
|
|
lhs.id == rhs.id
|
|
}
|
|
}
|
|
|
|
extension FileResource: Hashable {
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(id)
|
|
}
|
|
}
|
|
|
|
extension FileResource: Comparable {
|
|
|
|
static func < (lhs: FileResource, rhs: FileResource) -> Bool {
|
|
lhs.id < rhs.id
|
|
}
|
|
}
|