Merge pull request #316 from SSylvain1989/feature/notes-auto-save

Feat: notes auto save
This commit is contained in:
Hariharan Mudaliar 2026-03-04 20:24:21 +05:30 • committed by GitHub
commit e38cf03b7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -36,6 +36,7 @@ struct NotchNotesView: View {
@State private var editorImageData: Data? = nil @State private var editorImageData: Data? = nil
@State private var editorColorIndex: Int = 0 @State private var editorColorIndex: Int = 0
@State private var editorNoteId: UUID? @State private var editorNoteId: UUID?
@State private var autoSaveTask: Task<Void, Never>?
@Default(.enableNotes) var enableNotes @Default(.enableNotes) var enableNotes
@ -102,6 +103,9 @@ struct NotchNotesView: View {
updateLayoutState() updateLayoutState()
} }
.onDisappear { .onDisappear {
if isEditingNewNote || selectedNoteId != nil {
persistNote()
}
coordinator.notesLayoutState = .list coordinator.notesLayoutState = .list
} }
.onChange(of: isEditingNewNote) { _, _ in .onChange(of: isEditingNewNote) { _, _ in
@ -119,6 +123,15 @@ struct NotchNotesView: View {
.onChange(of: enableNotes) { _, _ in .onChange(of: enableNotes) { _, _ in
updateLayoutState() updateLayoutState()
} }
.onChange(of: editorContent) { _, _ in
scheduleAutoSave()
}
.onChange(of: editorTitle) { _, _ in
scheduleAutoSave()
}
.onChange(of: editorColorIndex) { _, _ in
scheduleAutoSave()
}
} }
// MARK: - Actions // MARK: - Actions
@ -197,48 +210,68 @@ struct NotchNotesView: View {
isEditingNewNote = false isEditingNewNote = false
} }
private func saveNote() { private func persistNote() {
guard let id = editorNoteId else { return }
let isExistingNote = savedNotes.contains(where: { $0.id == id })
if !isExistingNote && editorTitle.isEmpty && editorContent.isEmpty && editorImageData == nil {
return
}
var notes = savedNotes var notes = savedNotes
let now = Date() let now = Date()
if let id = editorNoteId { var fileName: String? = nil
// Priority: Save image to disk if it exists if let data = editorImageData {
var fileName: String? = nil let name = "note_image_\(id.uuidString).png"
if let data = editorImageData { let fileURL = NoteItem.noteImageDataDirectory.appendingPathComponent(name)
let name = "note_image_\(id.uuidString).png" try? data.write(to: fileURL)
let fileURL = NoteItem.noteImageDataDirectory.appendingPathComponent(name) fileName = name
try? data.write(to: fileURL) }
fileName = name
if let index = notes.firstIndex(where: { $0.id == id }) {
// Update
if let oldFileName = notes[index].imageFileName, oldFileName != fileName {
let oldFileURL = NoteItem.noteImageDataDirectory.appendingPathComponent(oldFileName)
try? FileManager.default.removeItem(at: oldFileURL)
} }
if let index = notes.firstIndex(where: { $0.id == id }) { notes[index].title = editorTitle
// Update notes[index].content = editorContent
// If there was an old image and it's being replaced or removed, delete old file notes[index].imageFileName = fileName
if let oldFileName = notes[index].imageFileName, oldFileName != fileName { notes[index].colorIndex = editorColorIndex
let oldFileURL = NoteItem.noteImageDataDirectory.appendingPathComponent(oldFileName) } else {
try? FileManager.default.removeItem(at: oldFileURL) // Create
} let newNote = NoteItem(
id: id,
notes[index].title = editorTitle title: editorTitle.isEmpty ? "Untitled Note" : editorTitle,
notes[index].content = editorContent content: editorContent,
notes[index].imageFileName = fileName creationDate: now,
notes[index].colorIndex = editorColorIndex colorIndex: editorColorIndex,
} else { isPinned: false,
// Create imageFileName: fileName
let newNote = NoteItem( )
id: id, notes.insert(newNote, at: 0)
title: editorTitle.isEmpty ? "Untitled Note" : editorTitle,
content: editorContent,
creationDate: now,
colorIndex: editorColorIndex,
isPinned: false,
imageFileName: fileName
)
notes.insert(newNote, at: 0)
}
savedNotes = notes // Persistence fix: save back to @Default
} }
savedNotes = notes
}
private func scheduleAutoSave() {
guard isEditingNewNote || selectedNoteId != nil else { return }
autoSaveTask?.cancel()
autoSaveTask = Task {
try? await Task.sleep(nanoseconds: 1_500_000_000)
guard !Task.isCancelled else { return }
await MainActor.run {
persistNote()
}
}
}
private func saveNote() {
persistNote()
closeEditor() closeEditor()
} }
@ -311,6 +344,7 @@ struct NotchNotesView: View {
} }
private func cancelEdit() { private func cancelEdit() {
persistNote()
closeEditor() closeEditor()
} }
@ -327,6 +361,8 @@ struct NotchNotesView: View {
} }
private func closeEditor() { private func closeEditor() {
autoSaveTask?.cancel()
autoSaveTask = nil
isEditingNewNote = false isEditingNewNote = false
selectedNoteId = nil selectedNoteId = nil
// Tiny delay to clear state after animation // Tiny delay to clear state after animation