197 lines
4.6 KiB
Swift
197 lines
4.6 KiB
Swift
import Foundation
|
|
import SwiftUI
|
|
import Combine
|
|
|
|
final class Content: ObservableObject {
|
|
|
|
@ObservedObject
|
|
var storage: Storage
|
|
|
|
@Published
|
|
var settings: Settings!
|
|
|
|
@Published
|
|
var posts: [Post]
|
|
|
|
@Published
|
|
var pages: [Page]
|
|
|
|
@Published
|
|
var tags: [Tag]
|
|
|
|
@Published
|
|
var files: [FileResource]
|
|
|
|
@Published
|
|
var tagOverview: Tag?
|
|
|
|
@Published
|
|
var results: GenerationResults
|
|
|
|
@Published
|
|
var storageErrors: [StorageError] = []
|
|
|
|
@Published
|
|
var generationStatus: String = "Ready to generate"
|
|
|
|
@Published
|
|
private(set) var isGeneratingWebsite = false
|
|
|
|
@Published
|
|
private(set) var shouldGenerateWebsite = false
|
|
|
|
@Published
|
|
private(set) var saveState: SaveState = .isSaved
|
|
|
|
let imageGenerator: ImageGenerator
|
|
|
|
var errorCallback: ((StorageError) -> Void)?
|
|
|
|
init() {
|
|
let settings = Settings.default
|
|
self.settings = settings
|
|
self.posts = []
|
|
self.pages = []
|
|
self.tags = []
|
|
self.files = []
|
|
self.tagOverview = nil
|
|
self.results = .init()
|
|
|
|
let storage = Storage()
|
|
self.storage = storage
|
|
self.imageGenerator = ImageGenerator(
|
|
storage: storage,
|
|
settings: settings)
|
|
storage.errorNotification = { [weak self] error in
|
|
self?.storageErrors.append(error)
|
|
}
|
|
settings.content = self
|
|
}
|
|
|
|
private func clear() {
|
|
self.settings = .default
|
|
self.posts = []
|
|
self.pages = []
|
|
self.tags = []
|
|
self.files = []
|
|
self.tagOverview = nil
|
|
self.results = .init()
|
|
}
|
|
|
|
var images: [FileResource] {
|
|
files.filter { $0.type.isImage }
|
|
}
|
|
|
|
func set(isGenerating: Bool) {
|
|
self.isGeneratingWebsite = isGenerating
|
|
}
|
|
|
|
func set(shouldGenerate: Bool) {
|
|
self.shouldGenerateWebsite = shouldGenerate
|
|
}
|
|
|
|
func add(_ file: FileResource) {
|
|
// TODO: Insert at correct index?
|
|
files.insert(file, at: 0)
|
|
}
|
|
|
|
func add(_ page: Page) {
|
|
// TODO: Insert at correct index?
|
|
pages.insert(page, at: 0)
|
|
}
|
|
|
|
func update(contentPath: URL, callback: @escaping () -> ()) {
|
|
guard storage.save(contentPath: contentPath) else {
|
|
return
|
|
}
|
|
loadFromDisk(callback: callback)
|
|
}
|
|
|
|
func remove(_ file: FileResource) {
|
|
files.remove(file)
|
|
for post in posts {
|
|
post.remove(file)
|
|
}
|
|
|
|
for page in pages {
|
|
page.remove(file)
|
|
}
|
|
|
|
for tag in tags {
|
|
tag.remove(file)
|
|
}
|
|
settings.remove(file)
|
|
}
|
|
|
|
func file(withOutputPath: String) -> FileResource? {
|
|
files.first { $0.absoluteUrl == withOutputPath }
|
|
}
|
|
|
|
func loadFromDisk(callback: @escaping () -> ()) {
|
|
DispatchQueue.global().async {
|
|
self.loadInBackground(callback: callback)
|
|
}
|
|
}
|
|
|
|
private func loadInBackground(callback: @escaping () -> ()) {
|
|
let loader = ModelLoader(content: self, storage: self.storage)
|
|
let result = loader.load()
|
|
|
|
DispatchQueue.main.async {
|
|
self.files = result.files
|
|
self.posts = result.posts
|
|
self.pages = result.pages
|
|
self.tags = result.tags
|
|
self.settings = result.settings
|
|
self.tagOverview = result.tagOverview
|
|
self.storageErrors.append(contentsOf: result.errors)
|
|
if !result.errors.isEmpty {
|
|
self.saveState = .savingPausedDueToLoadErrors
|
|
} else {
|
|
self.saveState = .isSaved
|
|
}
|
|
callback()
|
|
self.generateMissingVideoThumbnails()
|
|
}
|
|
}
|
|
|
|
func resumeSavingAfterLoadingErrors() {
|
|
saveState = .needsSave
|
|
saveIfNeeded()
|
|
}
|
|
|
|
func generateMissingVideoThumbnails() {
|
|
Task {
|
|
for file in self.files {
|
|
guard file.type.isVideo else { continue }
|
|
guard !file.isExternallyStored else { continue }
|
|
guard !storage.hasVideoThumbnail(for: file.id) else { continue }
|
|
if await imageGenerator.createVideoThumbnail(for: file.id) {
|
|
print("Generated thumbnail for \(file.id)")
|
|
file.didChange()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Saving
|
|
|
|
private(set) var lastSave: Date = .now
|
|
|
|
private(set) var lastModification: Date = .now
|
|
|
|
func update(saveState: SaveState) {
|
|
DispatchQueue.main.async {
|
|
self.saveState = saveState
|
|
}
|
|
}
|
|
|
|
func setModificationTimestamp() {
|
|
self.lastModification = .now
|
|
}
|
|
|
|
func setLastSaveTimestamp() {
|
|
self.lastSave = .now
|
|
}
|
|
}
|