From c1a3d220024c6ec52b5a36324872c74a09143f53 Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Tue, 14 Jan 2025 20:18:26 +0100 Subject: [PATCH] Allow text file editing --- CHDataManagement/Main/MainView.swift | 1 - CHDataManagement/Model/FileResource.swift | 4 ++ .../Storage/SecurityBookmark.swift | 9 ++-- CHDataManagement/Storage/Storage.swift | 6 +++ .../Views/Files/TextFileContentView.swift | 54 +++++++++++++++---- 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/CHDataManagement/Main/MainView.swift b/CHDataManagement/Main/MainView.swift index f8dcfb9..085d700 100644 --- a/CHDataManagement/Main/MainView.swift +++ b/CHDataManagement/Main/MainView.swift @@ -17,7 +17,6 @@ import SFSafeSymbols - Posts: Generate separate pages for posts to link to - Settings: Introduce `Authors` (`name`, `image`, `description`) - Page: Property `author` - - Text file editing - Blocks: Convert more commands to blocks - Graphs, Map, GPX for hikes diff --git a/CHDataManagement/Model/FileResource.swift b/CHDataManagement/Model/FileResource.swift index 765f25c..0abfa8c 100644 --- a/CHDataManagement/Model/FileResource.swift +++ b/CHDataManagement/Model/FileResource.swift @@ -98,6 +98,10 @@ final class FileResource: Item, LocalizedItem { content.storage.fileContent(for: id) ?? "" } + func save(textContent: String) -> Bool { + content.storage.save(fileContent: textContent, for: id) + } + func dataContent() -> Foundation.Data? { content.storage.fileData(for: id) } diff --git a/CHDataManagement/Storage/SecurityBookmark.swift b/CHDataManagement/Storage/SecurityBookmark.swift index 48dcd83..7d68d94 100644 --- a/CHDataManagement/Storage/SecurityBookmark.swift +++ b/CHDataManagement/Storage/SecurityBookmark.swift @@ -71,12 +71,15 @@ struct SecurityBookmark { return write(data, to: relativePath) } - func write(_ string: String, + /** + Write text to a file at the relative path. + */ + func write(_ content: String, to relativePath: String, createParentFolder: Bool = true, ifFileExists overwrite: OverwriteBehaviour = .writeIfChanged) -> Bool { - guard let data = string.data(using: .utf8) else { - delegate?.securityBookmark(error: "Failed to encode string to write to \(relativePath)") + guard let data = content.data(using: .utf8) else { + delegate?.securityBookmark(error: "Failed to encode content to write to \(relativePath)") return false } return write(data, to: relativePath, createParentFolder: createParentFolder, ifFileExists: overwrite) diff --git a/CHDataManagement/Storage/Storage.swift b/CHDataManagement/Storage/Storage.swift index 045c506..59d7fe2 100644 --- a/CHDataManagement/Storage/Storage.swift +++ b/CHDataManagement/Storage/Storage.swift @@ -360,6 +360,12 @@ final class Storage: ObservableObject { return contentScope.readData(at: path) } + func save(fileContent: String, for fileId: String) -> Bool { + guard let contentScope else { return false } + let path = filePath(file: fileId) + return contentScope.write(fileContent, to: path) + } + // MARK: Settings func loadSettings() -> Settings.Data? { diff --git a/CHDataManagement/Views/Files/TextFileContentView.swift b/CHDataManagement/Views/Files/TextFileContentView.swift index ba2915d..f7aa1f4 100644 --- a/CHDataManagement/Views/Files/TextFileContentView.swift +++ b/CHDataManagement/Views/Files/TextFileContentView.swift @@ -8,31 +8,65 @@ struct TextFileContentView: View { @State private var fileContent: String = "" + @State + private var loadedFile: String? + var body: some View { - if fileContent != "" { - TextEditor(text: $fileContent) - .font(.body.monospaced()) - .textEditorStyle(.plain) - //.background(.clear) - } else { - VStack { + VStack { + if fileContent != "" { + HStack { + Button("Reload", action: reload) + Button("Save", action: save) + Spacer() + } + TextEditor(text: $fileContent) + .font(.body.monospaced()) + .textEditorStyle(.plain) + .foregroundStyle(.primary) + } else { Image(systemSymbol: .docText) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 150) - Text("No preview available") + Text("No preview available or empty file") .font(.title) } - .foregroundStyle(.secondary) - .onAppear(perform: loadFileContent) } + .foregroundStyle(.secondary) + .onAppear(perform: loadFileContent) + .onDisappear(perform: save) } private func loadFileContent() { guard fileContent == "" else { return } + reload() + } + + private func reload() { fileContent = file.textContent() + loadedFile = file.id print("Loaded content of file \(file.id)") } + + private func save() { + guard let loadedFile else { + print("[ERROR] Text File View: No file loaded to save") + return + } + guard loadedFile == file.id else { + print("[ERROR] Text File View: Not saving since file changed") + return + } + guard fileContent != "" else { + print("Text File View: Not saving empty file \(file.id)") + return + } + guard file.save(textContent: fileContent) else { + print("[ERROR] Text File View: Failed to save file \(file.id)") + return + } + print("Text File View: Saved file \(file.id)") + } }