Files
conjure/Sources/ConjureKit/NotesStore.swift
T

75 lines
2.8 KiB
Swift

import AppKit
public struct Note: Identifiable {
public let id: UUID
public let contents: NSAttributedString
public let title: String
init(id: UUID, contents: NSAttributedString) {
self.id = id
self.contents = NSAttributedString(attributedString: contents)
var title = "Untitled Note"
contents.string.enumerateLines { line, stop in
let trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmed.isEmpty {
title = String(trimmed.prefix(60))
stop = true
}
}
self.title = title
}
}
@MainActor
public final class NotesStore {
public private(set) var notes: [Note] = []
private let directory: URL
public init(directory: URL = FileManager.default.urls(
for: .applicationSupportDirectory, in: .userDomainMask
)[0].appendingPathComponent("Conjure/Notes", isDirectory: true)) throws {
self.directory = directory
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
let files = try FileManager.default.contentsOfDirectory(
at: directory, includingPropertiesForKeys: nil
).filter { $0.pathExtension.lowercased() == "rtfd" }
.sorted { $0.lastPathComponent < $1.lastPathComponent }
notes = try files.map { url in
guard let id = UUID(uuidString: url.deletingPathExtension().lastPathComponent) else {
throw CocoaError(.fileReadCorruptFile)
}
let contents = try NSAttributedString(
url: url, options: [.documentType: NSAttributedString.DocumentType.rtfd],
documentAttributes: nil
)
return Note(id: id, contents: contents)
}
}
public func create() throws -> UUID {
let note = Note(id: UUID(), contents: NSAttributedString(string: ""))
try save(note)
notes.append(note)
notes.sort { $0.id.uuidString < $1.id.uuidString }
return note.id
}
public func update(id: UUID, contents: NSAttributedString) throws {
guard let index = notes.firstIndex(where: { $0.id == id }) else {
throw CocoaError(.fileNoSuchFile)
}
let note = Note(id: id, contents: contents)
try save(note)
notes[index] = note
}
private func save(_ note: Note) throws {
let wrapper = try note.contents.fileWrapper(
from: NSRange(location: 0, length: note.contents.length),
documentAttributes: [.documentType: NSAttributedString.DocumentType.rtfd]
)
let url = directory.appendingPathComponent(note.id.uuidString + ".rtfd", isDirectory: true)
try wrapper.write(to: url, options: .atomic, originalContentsURL: url)
}
}