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

140 lines
5.6 KiB
Swift

import SwiftUI
// MARK: - Shortcuts
struct ShortcutsView: View {
var body: some View {
DetailScaffold(
title: "Shortcuts",
subtitle: "Global hotkeys that work in every app."
) {
Card {
shortcutRow(name: "Fix selection", keys: ["⌘", ";"], detail: "Grammar + clarity, in place")
Divider()
shortcutRow(name: "Ask GrammaGem", keys: ["⌘", "'"], detail: "Rewrite with an instruction")
}
Card {
Label("Custom shortcuts", systemImage: "wand.and.stars")
.font(.headline)
Text("A built-in recorder for fully customizable shortcuts is on the roadmap. For now the defaults above are active system-wide.")
.font(.callout).foregroundStyle(.secondary)
}
}
}
private func shortcutRow(name: String, keys: [String], detail: String) -> some View {
HStack {
VStack(alignment: .leading, spacing: 2) {
Text(name).fontWeight(.medium)
Text(detail).font(.caption).foregroundStyle(.secondary)
}
Spacer()
HStack(spacing: 4) {
ForEach(keys, id: \.self) { k in
Text(k)
.font(.system(.body, design: .monospaced))
.padding(.horizontal, 8).padding(.vertical, 4)
.background(Color(nsColor: .controlColor), in: RoundedRectangle(cornerRadius: 6))
.overlay(RoundedRectangle(cornerRadius: 6).stroke(Color.primary.opacity(0.12)))
}
}
}
}
}
// MARK: - AI Model
struct ModelView: View {
@EnvironmentObject private var app: AppState
@EnvironmentObject private var gate: FeatureGate
@EnvironmentObject private var model: ModelManager
var body: some View {
DetailScaffold(
title: "AI Model",
subtitle: "The local model that powers rewrites, tone, and Ask. Runs entirely on your Mac."
) {
Card {
Picker("Model", selection: $model.selectedRepo) {
Text("Qwen2.5-3B · balanced (default)").tag(AppConfig.Model.defaultRepo)
Text("Qwen2.5-7B · higher quality").tag(AppConfig.Model.largeRepo)
}
.disabled(!gate.entitlements.canUseLargeModel)
if !gate.entitlements.canUseLargeModel {
HStack { Image(systemName: "lock.fill").foregroundStyle(GG.gold); Text("The larger model is available on the lifetime license.").font(.caption).foregroundStyle(.secondary) }
}
Divider()
ModelDownloadControls().environmentObject(app)
}
Card {
Label("Private by default", systemImage: "lock.shield")
.font(.headline)
Text("The model is downloaded once from Hugging Face and then runs offline. It is never bundled in the app, and it never sends your text anywhere.")
.font(.callout).foregroundStyle(.secondary)
}
}
}
}
// MARK: - Privacy
struct PrivacyView: View {
@EnvironmentObject private var usage: UsageStats
@State private var confirmReset = false
var body: some View {
DetailScaffold(
title: "Privacy",
subtitle: "What touches the network — and what never does."
) {
Card {
HStack(spacing: 10) {
Image(systemName: "checkmark.shield.fill").font(.title2).foregroundStyle(GG.emerald)
VStack(alignment: .leading, spacing: 2) {
Text("0 bytes of your writing leave this Mac").font(.headline)
Text("Every correction and rewrite runs locally. No telemetry is collected.")
.font(.callout).foregroundStyle(.secondary)
}
}
}
Card {
Text("The only times GrammaGem uses the network").font(.headline)
networkRow("One-time AI model download", "Hugging Face, on first run")
Divider()
networkRow("License activation & checks", "To enforce your device cap")
Divider()
networkRow("App updates", "Signed update checks")
Text("None of these ever include the text you write.")
.font(.caption).foregroundStyle(.secondary)
}
Card {
Text("Local data").font(.headline)
Text("Your dictionary, snippets, modes, and usage counts live only on this Mac.")
.font(.callout).foregroundStyle(.secondary)
Button(role: .destructive) { confirmReset = true } label: {
Label("Reset usage statistics", systemImage: "arrow.counterclockwise")
}
.confirmationDialog("Reset all local usage statistics?", isPresented: $confirmReset) {
Button("Reset", role: .destructive) { usage.reset() }
Button("Cancel", role: .cancel) {}
}
}
}
}
private func networkRow(_ title: String, _ detail: String) -> some View {
HStack(spacing: 10) {
Image(systemName: "arrow.up.forward.circle").foregroundStyle(.secondary)
VStack(alignment: .leading, spacing: 1) {
Text(title)
Text(detail).font(.caption).foregroundStyle(.secondary)
}
Spacer()
}
}
}