Add project save and load controls
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user