ChWebsiteApp/CHDataManagement/Model/FileResource.swift
2024-12-14 18:26:11 +01:00

162 lines
3.9 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
}
}
// MARK: File
func update(id newId: String) -> Bool {
guard !isExternallyStored else {
id = newId
return true
}
do {
try content.storage.move(file: id, to: newId)
id = newId
return true
} catch {
print("Failed to move file \(id) to \(newId)")
return false
}
}
}
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
}
}