Add project save and load controls

This commit is contained in:
Mikei386
2026-06-05 08:08:38 +02:00
parent a6d88a18d9
commit 52a2c9bf83
2 changed files with 64 additions and 0 deletions
+28
View File
@@ -39,6 +39,11 @@ struct ContentView: View {
) {
selectOutputFile()
}
Button("Projekt laden") {
selectProjectFile()
}
.help("Lädt eine gespeicherte .growthlapse-project.json, inklusive Segmentfenstern und Variantenwahl.")
}
.disabled(processor.state.isRunning)
@@ -365,6 +370,12 @@ struct ContentView: View {
.disabled(processor.state.isRunning || !project.clips.contains(where: \.needsRender))
.help("Rendert nur geänderte normalisierte Clips neu und baut danach das finale Video erneut.")
Button("Projekt speichern") {
processor.saveCurrentProject()
}
.disabled(processor.state.isRunning)
.help("Speichert die aktuelle Nachbearbeitung in die .growthlapse-project.json neben der Output-Datei. Segmentänderungen werden zusätzlich automatisch gespeichert.")
Button("Ergebnis bestätigen") {
processor.confirmProjectAndDeleteCache()
}
@@ -619,6 +630,23 @@ struct ContentView: View {
}
}
private func selectProjectFile() {
let panel = NSOpenPanel()
panel.title = "GrowthLapse-Projekt laden"
panel.canChooseFiles = true
panel.canChooseDirectories = false
panel.allowsMultipleSelection = false
panel.allowedContentTypes = [.json]
panel.directoryURL = settings.outputFile?.deletingLastPathComponent()
if panel.runModal() == .OK,
let url = panel.url,
let project = processor.loadProject(from: url) {
settings.outputFile = project.outputFileURL
settings.inputFolder = project.clips.first?.sourceURL.deletingLastPathComponent()
selectedClipID = project.clips.first?.id
}
}
private func selectExecutable(title: String, onSelect: (URL) -> Void) {
let panel = NSOpenPanel()
panel.title = title
+36
View File
@@ -137,6 +137,42 @@ final class VideoProcessor: ObservableObject {
saveProject(reordered)
}
func saveCurrentProject() {
guard let project else {
appendLog("Kein Projekt zum Speichern geladen.")
return
}
saveProject(project)
appendLog("Projekt gespeichert: \(GrowthLapseProject.url(for: project.outputFileURL).path)")
}
func loadProject(from url: URL) -> GrowthLapseProject? {
do {
let data = try Data(contentsOf: url)
var loadedProject = try JSONDecoder().decode(GrowthLapseProject.self, from: data)
loadedProject.clips = loadedProject.clips.map { clip in
var updated = clip
if !FileManager.default.fileExists(atPath: updated.normalizedClipPath) {
updated.needsRender = true
}
return updated
}
project = loadedProject
state = .finished(loadedProject.outputFileURL)
progress = 1
progressText = "Projekt geladen"
appendLog("Projekt geladen: \(url.path)")
if loadedProject.clips.contains(where: \.needsRender) {
appendLog("Hinweis: Einige Cache-Clips fehlen und werden beim nächsten Render neu erzeugt.")
}
return loadedProject
} catch {
state = .failed("Projekt konnte nicht geladen werden: \(error.localizedDescription)")
appendLog("Fehler: Projekt konnte nicht geladen werden: \(error.localizedDescription)")
return nil
}
}
func confirmProjectAndDeleteCache() {
guard let project else {
return