Save and check page content automatically
This commit is contained in:
parent
41171c31db
commit
7ebc9d8404
@ -155,6 +155,14 @@ final class Page: Item, DateItem, LocalizedItem {
|
||||
content.storage.pageContent(for: id, language: language)
|
||||
}
|
||||
|
||||
func removeContent(in language: ContentLanguage) -> Bool {
|
||||
guard content.storage.remove(pageContent: id, in: language) else {
|
||||
return false
|
||||
}
|
||||
localized(in: language).hasContent = false
|
||||
return true
|
||||
}
|
||||
|
||||
func save(pageContent: String, in language: ContentLanguage) -> Bool {
|
||||
guard content.storage.save(pageContent: pageContent, for: id, in: language) else {
|
||||
return false
|
||||
|
@ -77,6 +77,12 @@ final class Storage: ObservableObject {
|
||||
return contentScope.write(pageContent, to: path)
|
||||
}
|
||||
|
||||
func remove(pageContent pageId: String, in language: ContentLanguage) -> Bool {
|
||||
guard let contentScope else { return false }
|
||||
let path = pageContentPath(page: pageId, language: language)
|
||||
return contentScope.deleteFile(at: path)
|
||||
}
|
||||
|
||||
func save(page: Page.Data, for pageId: String) -> Bool {
|
||||
guard let contentScope else { return false }
|
||||
let path = pageMetadataPath(page: pageId)
|
||||
|
@ -2,6 +2,37 @@ import SwiftUI
|
||||
import SFSafeSymbols
|
||||
import HighlightedTextEditor
|
||||
|
||||
enum PageContentSaveStatus {
|
||||
case isSaved
|
||||
case failedToSave
|
||||
case needsSave
|
||||
case notLoaded
|
||||
|
||||
var symbol: SFSymbol {
|
||||
switch self {
|
||||
case .notLoaded:
|
||||
return .questionmarkSquareDashed
|
||||
case .isSaved:
|
||||
return .checkmarkCircleFill
|
||||
case .needsSave:
|
||||
return .hourglassCircleFill
|
||||
case .failedToSave:
|
||||
return .exclamationmarkTriangleFill
|
||||
}
|
||||
}
|
||||
|
||||
var color: Color {
|
||||
switch self {
|
||||
case .isSaved, .notLoaded:
|
||||
return .green
|
||||
case .needsSave:
|
||||
return .yellow
|
||||
case .failedToSave:
|
||||
return .red
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalizedPageContentView: View {
|
||||
|
||||
@EnvironmentObject
|
||||
@ -15,36 +46,23 @@ struct LocalizedPageContentView: View {
|
||||
@State
|
||||
private var pageContent: String = ""
|
||||
|
||||
@State
|
||||
private var pageContentUsedForGeneration: String = ""
|
||||
|
||||
@State
|
||||
private var generationResults: PageGenerationResults?
|
||||
|
||||
@State
|
||||
private var didChangeContent = false
|
||||
private var saveState: PageContentSaveStatus = .notLoaded
|
||||
|
||||
@State
|
||||
private var lastSave: Date = .now
|
||||
|
||||
@State
|
||||
private var lastModification: Date = .now
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
HStack(alignment: .firstTextBaseline) {
|
||||
Button(action: loadContent) {
|
||||
Text("Load")
|
||||
}
|
||||
Button(action: saveContent) {
|
||||
Text("Save")
|
||||
}
|
||||
Button(action: checkContent) {
|
||||
Text("Check")
|
||||
}.disabled(content.isGeneratingWebsite)
|
||||
if content.isGeneratingWebsite {
|
||||
ProgressView()
|
||||
.scaleEffect(0.6)
|
||||
.frame(height: 15)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
|
||||
HStack {
|
||||
Image(systemSymbol: saveState.symbol)
|
||||
.foregroundStyle(saveState.color)
|
||||
if let generationResults {
|
||||
PageContentResultsView(results: generationResults)
|
||||
}
|
||||
@ -59,69 +77,94 @@ struct LocalizedPageContentView: View {
|
||||
text: $pageContent,
|
||||
highlightRules: .markdown)
|
||||
.onChange(of: pageContent) {
|
||||
didChangeContent = true
|
||||
didChangeContent()
|
||||
}
|
||||
}
|
||||
.onAppear(perform: loadContent)
|
||||
.onDisappear(perform: saveContent)
|
||||
.onDisappear { saveContentIfNeeded(isFinalSave: true) }
|
||||
}
|
||||
|
||||
private func didChangeContent() {
|
||||
if saveState == .notLoaded {
|
||||
// Content was changed due to loading
|
||||
saveState = .isSaved
|
||||
return
|
||||
}
|
||||
saveState = .needsSave
|
||||
|
||||
// Wait a few seconds for a save, to allow additional changes
|
||||
// Reduces the number of saves
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(10)) {
|
||||
self.saveContentIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadContent() {
|
||||
let language = language
|
||||
guard page.localized(in: language).hasContent else {
|
||||
pageContent = "New file"
|
||||
DispatchQueue.main.async {
|
||||
didChangeContent = false
|
||||
}
|
||||
return
|
||||
}
|
||||
guard let content = page.pageContent(in: language) else {
|
||||
print("Failed to load page content")
|
||||
pageContent = "Failed to load"
|
||||
DispatchQueue.main.async {
|
||||
didChangeContent = false
|
||||
}
|
||||
return
|
||||
}
|
||||
guard content != "" else {
|
||||
pageContent = "New file"
|
||||
DispatchQueue.main.async {
|
||||
didChangeContent = false
|
||||
}
|
||||
return
|
||||
}
|
||||
pageContent = content
|
||||
checkContent()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
didChangeContent = false
|
||||
}
|
||||
}
|
||||
|
||||
private func saveContent() {
|
||||
private func saveContentIfNeeded(isFinalSave: Bool = false) {
|
||||
switch saveState {
|
||||
case .isSaved, .notLoaded:
|
||||
return
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if !isFinalSave, Date.now.timeIntervalSince(lastModification) < 10 {
|
||||
// Additional modification made
|
||||
// Wait for next scheduled invocation of saveIfNeeded()
|
||||
// if the overall unsaved time is not too long
|
||||
if Date.now.timeIntervalSince(lastSave) < 60 {
|
||||
//print("Waiting while modifying")
|
||||
return
|
||||
}
|
||||
print("Saving content after 30 seconds of modifications")
|
||||
}
|
||||
saveUnconditionally()
|
||||
}
|
||||
|
||||
private func saveUnconditionally() {
|
||||
guard pageContent != "New file", pageContent != "" else {
|
||||
// TODO: Delete file?
|
||||
return
|
||||
}
|
||||
guard didChangeContent else {
|
||||
guard page.removeContent(in: language) else {
|
||||
print("Failed to remove empty content from disk")
|
||||
saveState = .failedToSave
|
||||
return
|
||||
}
|
||||
saveState = .notLoaded
|
||||
generationResults = nil
|
||||
return
|
||||
}
|
||||
|
||||
guard page.save(pageContent: pageContent, in: language) else {
|
||||
print("Failed to save content")
|
||||
saveState = .failedToSave
|
||||
return
|
||||
}
|
||||
didChangeContent = false
|
||||
saveState = .isSaved
|
||||
checkContent()
|
||||
}
|
||||
|
||||
private func checkContent() {
|
||||
let content = self.pageContent
|
||||
guard content != pageContentUsedForGeneration else {
|
||||
return
|
||||
}
|
||||
guard !self.content.isGeneratingWebsite else {
|
||||
return
|
||||
}
|
||||
self.content.check(content: content, of: page, for: language) {
|
||||
self.content.check(content: pageContent, of: page, for: language) {
|
||||
self.generationResults = $0
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user