mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Merge pull request #316 from SSylvain1989/feature/notes-auto-save
Feat: notes auto save
This commit is contained in:
commit
e38cf03b7f
1 changed files with 72 additions and 36 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue