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,12 +210,17 @@ 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 {
// Priority: Save image to disk if it exists
var fileName: String? = nil var fileName: String? = nil
if let data = editorImageData { if let data = editorImageData {
let name = "note_image_\(id.uuidString).png" let name = "note_image_\(id.uuidString).png"
@ -213,7 +231,6 @@ struct NotchNotesView: View {
if let index = notes.firstIndex(where: { $0.id == id }) { if let index = notes.firstIndex(where: { $0.id == id }) {
// Update // Update
// If there was an old image and it's being replaced or removed, delete old file
if let oldFileName = notes[index].imageFileName, oldFileName != fileName { if let oldFileName = notes[index].imageFileName, oldFileName != fileName {
let oldFileURL = NoteItem.noteImageDataDirectory.appendingPathComponent(oldFileName) let oldFileURL = NoteItem.noteImageDataDirectory.appendingPathComponent(oldFileName)
try? FileManager.default.removeItem(at: oldFileURL) try? FileManager.default.removeItem(at: oldFileURL)
@ -236,9 +253,25 @@ struct NotchNotesView: View {
) )
notes.insert(newNote, at: 0) 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