grammargem/Sources/GrammaGem/System/SnippetStore.swift
BigMarc a7bf45b466 Add management window; sales-focused README; FounderGem LLC
- Management app: sidebar window with Dashboard (usage insights), Devices
  (slot usage, deactivate this Mac), Writing Modes (custom + app-aware map),
  Dictionary, Snippets, Shortcuts, AI Model, Privacy, General, License, About.
- New local stores: Preferences (launch-at-login, appearance), UsageStats
  (privacy-friendly local insights), CustomModesStore, SnippetStore.
- License model now tracks device name + activation usage/limit for the
  Devices screen.
- README rewritten as a conversion-focused product page (no internal cost/setup).
- Legal entity set to FounderGem LLC across README, LICENSE, Info.plist, About.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:28:23 +02:00

52 lines
1.5 KiB
Swift

import Foundation
/// A text-expansion snippet: type a short trigger, get a longer expansion.
struct Snippet: Codable, Identifiable, Equatable {
var id = UUID()
var trigger: String
var expansion: String
}
/// Local store for text-expansion snippets (a paid feature). Persisted to disk;
/// snippet contents never leave the device.
@MainActor
final class SnippetStore: ObservableObject {
@Published private(set) var snippets: [Snippet]
private let key = "GrammaGem.snippets"
private let d = UserDefaults.standard
init() {
if let raw = d.data(forKey: key),
let decoded = try? JSONDecoder().decode([Snippet].self, from: raw) {
snippets = decoded
} else {
snippets = []
}
}
func add(trigger: String, expansion: String) {
let t = trigger.trimmingCharacters(in: .whitespaces)
let e = expansion.trimmingCharacters(in: .whitespacesAndNewlines)
guard !t.isEmpty, !e.isEmpty else { return }
snippets.append(Snippet(trigger: t, expansion: e))
persist()
}
func remove(_ snippet: Snippet) {
snippets.removeAll { $0.id == snippet.id }
persist()
}
/// Resolve a trigger to its expansion (used by the snippet hotkey path).
func expansion(for trigger: String) -> String? {
snippets.first { $0.trigger == trigger }?.expansion
}
private func persist() {
if let raw = try? JSONEncoder().encode(snippets) {
d.set(raw, forKey: key)
}
}
}