添加收集箱与快捷指令保存功能
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// ClipStore.swift
|
||||
// Note
|
||||
//
|
||||
// Created by Kimi Code CLI on 2026/7/15.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Clip: Codable, Identifiable, Equatable, Sendable {
|
||||
let id: UUID
|
||||
var text: String
|
||||
let createdAt: Date
|
||||
var source: String?
|
||||
|
||||
nonisolated init(id: UUID = UUID(), text: String, createdAt: Date = Date(), source: String? = nil) {
|
||||
self.id = id
|
||||
self.text = text
|
||||
self.createdAt = createdAt
|
||||
self.source = source
|
||||
}
|
||||
}
|
||||
|
||||
actor ClipStore {
|
||||
|
||||
static let shared = ClipStore()
|
||||
|
||||
private let appGroupIdentifier = "group.com.fishestlife.note"
|
||||
private let fileName = "clips.json"
|
||||
private let subdirectory = "SharedFiles/Clips"
|
||||
|
||||
private var cachedClips: [Clip]?
|
||||
|
||||
private var fileURL: URL {
|
||||
let fileManager = FileManager.default
|
||||
guard let containerURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) else {
|
||||
fatalError("无法访问 App Group 容器: \(appGroupIdentifier)")
|
||||
}
|
||||
let directoryURL = containerURL.appendingPathComponent(subdirectory, isDirectory: true)
|
||||
try? fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true)
|
||||
return directoryURL.appendingPathComponent(fileName)
|
||||
}
|
||||
|
||||
private init() {}
|
||||
|
||||
func save(text: String, source: String? = nil) async throws {
|
||||
var clips = try await loadAll()
|
||||
let clip = Clip(text: text, source: source)
|
||||
clips.insert(clip, at: 0)
|
||||
try await persist(clips)
|
||||
}
|
||||
|
||||
func loadAll() async throws -> [Clip] {
|
||||
if let cached = cachedClips {
|
||||
return cached
|
||||
}
|
||||
|
||||
let url = fileURL
|
||||
let fileManager = FileManager.default
|
||||
guard fileManager.fileExists(atPath: url.path) else {
|
||||
cachedClips = []
|
||||
return []
|
||||
}
|
||||
|
||||
let data = try Data(contentsOf: url)
|
||||
let clips = try JSONDecoder().decode([Clip].self, from: data)
|
||||
cachedClips = clips
|
||||
return clips
|
||||
}
|
||||
|
||||
func delete(id: UUID) async throws {
|
||||
var clips = try await loadAll()
|
||||
clips.removeAll { $0.id == id }
|
||||
try await persist(clips)
|
||||
}
|
||||
|
||||
func clearAll() async throws {
|
||||
try await persist([])
|
||||
}
|
||||
|
||||
func count() async throws -> Int {
|
||||
let clips = try await loadAll()
|
||||
return clips.count
|
||||
}
|
||||
|
||||
private func persist(_ clips: [Clip]) async throws {
|
||||
let url = fileURL
|
||||
let data = try JSONEncoder().encode(clips)
|
||||
try data.write(to: url, options: .atomic)
|
||||
cachedClips = clips
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user