buildanything 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +55 -0
- package/README.md +71 -61
- package/agents/ios-app-review-guardian.md +49 -0
- package/agents/ios-foundation-models-specialist.md +46 -0
- package/agents/ios-storekit-specialist.md +52 -0
- package/agents/ios-swift-architect.md +102 -0
- package/agents/ios-swift-search.md +130 -0
- package/agents/ios-swift-ui-design.md +104 -0
- package/commands/build.md +80 -176
- package/commands/fix.md +65 -0
- package/commands/setup.md +73 -0
- package/commands/ux-review.md +63 -0
- package/commands/verify.md +72 -0
- package/hooks/session-start +18 -1
- package/package.json +5 -2
- package/protocols/brainstorm.md +99 -0
- package/protocols/build-fix.md +52 -0
- package/protocols/cleanup.md +54 -0
- package/protocols/design.md +269 -0
- package/protocols/eval-harness.md +61 -0
- package/protocols/fake-data-detector.md +64 -0
- package/protocols/ios-context.md +235 -0
- package/protocols/ios-frameworks-map.md +323 -0
- package/protocols/ios-phase-branches.md +162 -0
- package/protocols/ios-preflight.md +27 -0
- package/protocols/metric-loop.md +93 -0
- package/protocols/planning.md +87 -0
- package/protocols/smoke-test.md +110 -0
- package/protocols/verify.md +67 -0
- package/protocols/web-phase-branches.md +201 -0
- package/skills/ios/_VENDORED.md +60 -0
- package/skills/ios/activitykit/LICENSE +131 -0
- package/skills/ios/activitykit/SKILL.md +505 -0
- package/skills/ios/activitykit/references/activitykit-patterns.md +868 -0
- package/skills/ios/app-intents/LICENSE +131 -0
- package/skills/ios/app-intents/SKILL.md +494 -0
- package/skills/ios/app-intents/references/appintents-advanced.md +1076 -0
- package/skills/ios/apple-on-device-ai/LICENSE +131 -0
- package/skills/ios/apple-on-device-ai/SKILL.md +505 -0
- package/skills/ios/apple-on-device-ai/references/coreml-conversion.md +425 -0
- package/skills/ios/apple-on-device-ai/references/coreml-optimization.md +344 -0
- package/skills/ios/apple-on-device-ai/references/foundation-models.md +508 -0
- package/skills/ios/apple-on-device-ai/references/mlx-swift.md +285 -0
- package/skills/ios/ios-26-platform/SKILL.md +53 -0
- package/skills/ios/ios-26-platform/references/automatic-adoption.md +161 -0
- package/skills/ios/ios-26-platform/references/backward-compat.md +238 -0
- package/skills/ios/ios-26-platform/references/liquid-glass.md +255 -0
- package/skills/ios/ios-26-platform/references/swiftui-apis.md +277 -0
- package/skills/ios/ios-26-platform/references/toolbar-navigation.md +250 -0
- package/skills/ios/ios-bootstrap/SKILL.md +98 -0
- package/skills/ios/ios-bootstrap/references/apple-docs-mcp-config.md +28 -0
- package/skills/ios/ios-bootstrap/references/new-project-dialog.md +41 -0
- package/skills/ios/ios-bootstrap/references/xcode-mcp-config.md +29 -0
- package/skills/ios/ios-debugger-agent/LICENSE +21 -0
- package/skills/ios/ios-debugger-agent/SKILL.md +58 -0
- package/skills/ios/ios-debugger-agent/agents/openai.yaml +4 -0
- package/skills/ios/ios-entitlements-generator/SKILL.md +47 -0
- package/skills/ios/ios-hig/SKILL.md +41 -0
- package/skills/ios/ios-hig/references/accessibility.md +81 -0
- package/skills/ios/ios-hig/references/content.md +142 -0
- package/skills/ios/ios-hig/references/feedback.md +123 -0
- package/skills/ios/ios-hig/references/interaction.md +199 -0
- package/skills/ios/ios-hig/references/performance-platform.md +129 -0
- package/skills/ios/ios-hig/references/privacy-permissions.md +181 -0
- package/skills/ios/ios-hig/references/visual-design.md +84 -0
- package/skills/ios/ios-info-plist-hardening/SKILL.md +130 -0
- package/skills/ios/ios-maestro-flow-author/SKILL.md +68 -0
- package/skills/ios/ios-maestro-flow-author/references/input-and-scroll.yaml +17 -0
- package/skills/ios/ios-maestro-flow-author/references/modal-and-dismiss.yaml +14 -0
- package/skills/ios/ios-maestro-flow-author/references/onboarding-flow.yaml +16 -0
- package/skills/ios/ios-maestro-flow-author/references/tab-navigation.yaml +13 -0
- package/skills/ios/ios-maestro-flow-author/references/tap-and-assert.yaml +9 -0
- package/skills/ios/swift-accessibility/LICENSE +21 -0
- package/skills/ios/swift-accessibility/SKILL.md +371 -0
- package/skills/ios/swift-accessibility/examples/before-after-appkit.md +446 -0
- package/skills/ios/swift-accessibility/examples/before-after-swiftui.md +441 -0
- package/skills/ios/swift-accessibility/examples/before-after-uikit.md +464 -0
- package/skills/ios/swift-accessibility/references/assistive-access.md +441 -0
- package/skills/ios/swift-accessibility/references/display-settings.md +491 -0
- package/skills/ios/swift-accessibility/references/dynamic-type.md +420 -0
- package/skills/ios/swift-accessibility/references/media-accessibility.md +421 -0
- package/skills/ios/swift-accessibility/references/motor-input.md +393 -0
- package/skills/ios/swift-accessibility/references/nutrition-labels.md +362 -0
- package/skills/ios/swift-accessibility/references/platform-specifics.md +515 -0
- package/skills/ios/swift-accessibility/references/semantic-structure.md +585 -0
- package/skills/ios/swift-accessibility/references/testing-auditing.md +507 -0
- package/skills/ios/swift-accessibility/references/voice-control.md +317 -0
- package/skills/ios/swift-accessibility/references/voiceover-swiftui.md +584 -0
- package/skills/ios/swift-accessibility/references/voiceover-uikit.md +519 -0
- package/skills/ios/swift-accessibility/references/wcag-mapping.md +167 -0
- package/skills/ios/swift-accessibility/resources/audit-template.swift +128 -0
- package/skills/ios/swift-accessibility/resources/qa-checklist.md +258 -0
- package/skills/ios/swift-concurrency/LICENSE +21 -0
- package/skills/ios/swift-concurrency/SKILL.md +171 -0
- package/skills/ios/swift-concurrency/references/_index.md +50 -0
- package/skills/ios/swift-concurrency/references/actors.md +660 -0
- package/skills/ios/swift-concurrency/references/async-algorithms.md +847 -0
- package/skills/ios/swift-concurrency/references/async-await-basics.md +266 -0
- package/skills/ios/swift-concurrency/references/async-sequences.md +710 -0
- package/skills/ios/swift-concurrency/references/core-data.md +560 -0
- package/skills/ios/swift-concurrency/references/glossary.md +135 -0
- package/skills/ios/swift-concurrency/references/linting.md +155 -0
- package/skills/ios/swift-concurrency/references/memory-management.md +569 -0
- package/skills/ios/swift-concurrency/references/migration.md +1104 -0
- package/skills/ios/swift-concurrency/references/performance.md +593 -0
- package/skills/ios/swift-concurrency/references/sendable.md +598 -0
- package/skills/ios/swift-concurrency/references/tasks.md +636 -0
- package/skills/ios/swift-concurrency/references/testing.md +592 -0
- package/skills/ios/swift-concurrency/references/threading.md +495 -0
- package/skills/ios/swift-security-expert/LICENSE +21 -0
- package/skills/ios/swift-security-expert/SKILL.md +470 -0
- package/skills/ios/swift-security-expert/references/biometric-authentication.md +565 -0
- package/skills/ios/swift-security-expert/references/certificate-trust.md +592 -0
- package/skills/ios/swift-security-expert/references/common-anti-patterns.md +690 -0
- package/skills/ios/swift-security-expert/references/compliance-owasp-mapping.md +537 -0
- package/skills/ios/swift-security-expert/references/credential-storage-patterns.md +721 -0
- package/skills/ios/swift-security-expert/references/cryptokit-public-key.md +505 -0
- package/skills/ios/swift-security-expert/references/cryptokit-symmetric.md +497 -0
- package/skills/ios/swift-security-expert/references/keychain-access-control.md +508 -0
- package/skills/ios/swift-security-expert/references/keychain-fundamentals.md +596 -0
- package/skills/ios/swift-security-expert/references/keychain-item-classes.md +476 -0
- package/skills/ios/swift-security-expert/references/keychain-sharing.md +458 -0
- package/skills/ios/swift-security-expert/references/migration-legacy-stores.md +727 -0
- package/skills/ios/swift-security-expert/references/secure-enclave.md +539 -0
- package/skills/ios/swift-security-expert/references/testing-security-code.md +781 -0
- package/skills/ios/swift-testing-expert/LICENSE +21 -0
- package/skills/ios/swift-testing-expert/SKILL.md +79 -0
- package/skills/ios/swift-testing-expert/references/_index.md +12 -0
- package/skills/ios/swift-testing-expert/references/async-testing-and-waiting.md +127 -0
- package/skills/ios/swift-testing-expert/references/expectations.md +145 -0
- package/skills/ios/swift-testing-expert/references/fundamentals.md +141 -0
- package/skills/ios/swift-testing-expert/references/migration-from-xctest.md +127 -0
- package/skills/ios/swift-testing-expert/references/parallelization-and-isolation.md +95 -0
- package/skills/ios/swift-testing-expert/references/parameterized-testing.md +284 -0
- package/skills/ios/swift-testing-expert/references/performance-and-best-practices.md +187 -0
- package/skills/ios/swift-testing-expert/references/traits-and-tags.md +114 -0
- package/skills/ios/swift-testing-expert/references/xcode-workflows.md +70 -0
- package/skills/ios/swiftdata-pro/LICENSE +21 -0
- package/skills/ios/swiftdata-pro/SKILL.md +102 -0
- package/skills/ios/swiftdata-pro/agents/openai.yaml +10 -0
- package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.png +0 -0
- package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.svg +29 -0
- package/skills/ios/swiftdata-pro/references/class-inheritance.md +104 -0
- package/skills/ios/swiftdata-pro/references/cloudkit.md +10 -0
- package/skills/ios/swiftdata-pro/references/core-rules.md +20 -0
- package/skills/ios/swiftdata-pro/references/indexing.md +27 -0
- package/skills/ios/swiftdata-pro/references/predicates.md +73 -0
- package/skills/ios/swiftui-design-principles/AGENTS.md +21 -0
- package/skills/ios/swiftui-design-principles/LICENSE +21 -0
- package/skills/ios/swiftui-design-principles/README.md +41 -0
- package/skills/ios/swiftui-design-principles/SKILL.md +605 -0
- package/skills/ios/swiftui-design-principles/metadata.json +10 -0
- package/skills/ios/swiftui-liquid-glass/LICENSE +21 -0
- package/skills/ios/swiftui-liquid-glass/SKILL.md +95 -0
- package/skills/ios/swiftui-liquid-glass/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-liquid-glass/references/liquid-glass.md +280 -0
- package/skills/ios/swiftui-performance-audit/LICENSE +21 -0
- package/skills/ios/swiftui-performance-audit/SKILL.md +111 -0
- package/skills/ios/swiftui-performance-audit/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-performance-audit/references/code-smells.md +150 -0
- package/skills/ios/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/skills/ios/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/skills/ios/swiftui-performance-audit/references/profiling-intake.md +44 -0
- package/skills/ios/swiftui-performance-audit/references/report-template.md +47 -0
- package/skills/ios/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
- package/skills/ios/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
- package/skills/ios/swiftui-pro/LICENSE +21 -0
- package/skills/ios/swiftui-pro/SKILL.md +108 -0
- package/skills/ios/swiftui-pro/agents/openai.yaml +10 -0
- package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
- package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
- package/skills/ios/swiftui-pro/references/accessibility.md +13 -0
- package/skills/ios/swiftui-pro/references/api.md +39 -0
- package/skills/ios/swiftui-pro/references/data.md +43 -0
- package/skills/ios/swiftui-pro/references/design.md +31 -0
- package/skills/ios/swiftui-pro/references/hygiene.md +9 -0
- package/skills/ios/swiftui-pro/references/navigation.md +14 -0
- package/skills/ios/swiftui-pro/references/performance.md +46 -0
- package/skills/ios/swiftui-pro/references/swift.md +56 -0
- package/skills/ios/swiftui-pro/references/views.md +35 -0
- package/skills/ios/swiftui-ui-patterns/LICENSE +21 -0
- package/skills/ios/swiftui-ui-patterns/SKILL.md +100 -0
- package/skills/ios/swiftui-ui-patterns/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-ui-patterns/references/app-wiring.md +201 -0
- package/skills/ios/swiftui-ui-patterns/references/async-state.md +96 -0
- package/skills/ios/swiftui-ui-patterns/references/components-index.md +50 -0
- package/skills/ios/swiftui-ui-patterns/references/controls.md +57 -0
- package/skills/ios/swiftui-ui-patterns/references/deeplinks.md +66 -0
- package/skills/ios/swiftui-ui-patterns/references/focus.md +90 -0
- package/skills/ios/swiftui-ui-patterns/references/form.md +97 -0
- package/skills/ios/swiftui-ui-patterns/references/grids.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/haptics.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/input-toolbar.md +51 -0
- package/skills/ios/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
- package/skills/ios/swiftui-ui-patterns/references/list.md +86 -0
- package/skills/ios/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
- package/skills/ios/swiftui-ui-patterns/references/macos-settings.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/matched-transitions.md +59 -0
- package/skills/ios/swiftui-ui-patterns/references/media.md +73 -0
- package/skills/ios/swiftui-ui-patterns/references/menu-bar.md +101 -0
- package/skills/ios/swiftui-ui-patterns/references/navigationstack.md +159 -0
- package/skills/ios/swiftui-ui-patterns/references/overlay.md +45 -0
- package/skills/ios/swiftui-ui-patterns/references/performance.md +62 -0
- package/skills/ios/swiftui-ui-patterns/references/previews.md +48 -0
- package/skills/ios/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
- package/skills/ios/swiftui-ui-patterns/references/scrollview.md +87 -0
- package/skills/ios/swiftui-ui-patterns/references/searchable.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/sheets.md +155 -0
- package/skills/ios/swiftui-ui-patterns/references/split-views.md +72 -0
- package/skills/ios/swiftui-ui-patterns/references/tabview.md +114 -0
- package/skills/ios/swiftui-ui-patterns/references/theming.md +71 -0
- package/skills/ios/swiftui-ui-patterns/references/title-menus.md +93 -0
- package/skills/ios/swiftui-ui-patterns/references/top-bar.md +49 -0
- package/skills/ios/swiftui-view-refactor/LICENSE +21 -0
- package/skills/ios/swiftui-view-refactor/SKILL.md +207 -0
- package/skills/ios/swiftui-view-refactor/agents/openai.yaml +4 -0
- package/skills/ios/swiftui-view-refactor/references/mv-patterns.md +161 -0
- package/skills/ios/widgetkit/LICENSE +131 -0
- package/skills/ios/widgetkit/SKILL.md +502 -0
- package/skills/ios/widgetkit/references/widgetkit-advanced.md +871 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Interaction
|
|
2
|
+
|
|
3
|
+
Apple Human Interface Guidelines for touch targets, input, navigation, layout, and hierarchy.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Touch Targets and Input](#touch-targets-and-input)
|
|
7
|
+
2. [Navigation and Flows](#navigation-and-flows)
|
|
8
|
+
3. [Layout, Hierarchy, and Grouping](#layout-hierarchy-and-grouping)
|
|
9
|
+
|
|
10
|
+
## Touch Targets and Input
|
|
11
|
+
|
|
12
|
+
### Critical Rules
|
|
13
|
+
|
|
14
|
+
- Use system controls (`Button`, `Toggle`, `TextField`, `Picker`) rather than custom hit-testing
|
|
15
|
+
- Ensure **comfortable hit targets**; avoid tiny icons-only tap areas
|
|
16
|
+
- Prefer **clear labels** over icon-only actions; use SF Symbols consistently with text where appropriate
|
|
17
|
+
- Use appropriate keyboard/input behaviors (submit labels, autocorrection/capitalization) for the field's purpose
|
|
18
|
+
- Avoid gesture-only interactions for primary actions; make actions discoverable
|
|
19
|
+
|
|
20
|
+
### Examples
|
|
21
|
+
|
|
22
|
+
```swift
|
|
23
|
+
// ✅ Tappable control with label + icon; clear intent
|
|
24
|
+
Button("Add item", systemImage: "plus") {
|
|
25
|
+
model.add()
|
|
26
|
+
}
|
|
27
|
+
.buttonStyle(.borderedProminent)
|
|
28
|
+
|
|
29
|
+
// ✅ TextField with appropriate keyboard
|
|
30
|
+
TextField("Email", text: $email)
|
|
31
|
+
.keyboardType(.emailAddress)
|
|
32
|
+
.textInputAutocapitalization(.never)
|
|
33
|
+
.autocorrectionDisabled()
|
|
34
|
+
|
|
35
|
+
// ❌ Tiny icon-only tap target; poor discoverability
|
|
36
|
+
Image(systemName: "plus")
|
|
37
|
+
.onTapGesture {
|
|
38
|
+
model.add()
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Navigation and Flows
|
|
43
|
+
|
|
44
|
+
### Critical Rules
|
|
45
|
+
|
|
46
|
+
- Prefer **NavigationStack + navigationDestination** for drill-in flows; keep navigation shallow where possible
|
|
47
|
+
- Use **modals** for short, self-contained tasks (create, edit, pick); always provide a clear way to dismiss
|
|
48
|
+
- Keep **back behavior predictable**: don't override system expectations; preserve navigation state when reasonable
|
|
49
|
+
- Avoid "choice paralysis": limit top-level destinations; group related settings and utilities
|
|
50
|
+
- Prefer system placements: `.confirmationAction` for Save/Done, `.cancellationAction` for Cancel
|
|
51
|
+
|
|
52
|
+
### Examples
|
|
53
|
+
|
|
54
|
+
```swift
|
|
55
|
+
// ✅ Predictable drill-in navigation; modal only for creation
|
|
56
|
+
NavigationStack {
|
|
57
|
+
List(items) { item in
|
|
58
|
+
NavigationLink(item.title, value: item.id)
|
|
59
|
+
}
|
|
60
|
+
.navigationDestination(for: Item.ID.self) { id in
|
|
61
|
+
ItemDetailView(id: id)
|
|
62
|
+
}
|
|
63
|
+
.toolbar {
|
|
64
|
+
ToolbarItem(placement: .primaryAction) {
|
|
65
|
+
Button("Add", systemImage: "plus") { model.isPresentingCreate = true }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
.sheet(isPresented: $model.isPresentingCreate) {
|
|
69
|
+
NavigationStack { CreateItemView() }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ✅ Modal with clear dismiss path
|
|
74
|
+
NavigationStack {
|
|
75
|
+
CreateItemView()
|
|
76
|
+
.navigationTitle("New Item")
|
|
77
|
+
.toolbar {
|
|
78
|
+
ToolbarItem(placement: .cancellationAction) {
|
|
79
|
+
Button("Cancel", action: dismiss)
|
|
80
|
+
}
|
|
81
|
+
ToolbarItem(placement: .confirmationAction) {
|
|
82
|
+
Button("Save", action: model.save)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ❌ Everything is a modal; unclear back/exit paths
|
|
88
|
+
VStack {
|
|
89
|
+
Button("Open item") { model.showItem.toggle() }
|
|
90
|
+
}
|
|
91
|
+
.sheet(isPresented: $model.showItem) {
|
|
92
|
+
ItemDetailView(id: model.selectedID)
|
|
93
|
+
.toolbar { Button("Save") {} } // no Cancel, no navigation context
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Navigation Guidelines
|
|
98
|
+
|
|
99
|
+
**Use NavigationStack for**:
|
|
100
|
+
- Browsing hierarchical content
|
|
101
|
+
- Drill-down patterns
|
|
102
|
+
- Main app navigation
|
|
103
|
+
|
|
104
|
+
**Use Modals (.sheet, .fullScreenCover) for**:
|
|
105
|
+
- Creating new content
|
|
106
|
+
- Editing existing content
|
|
107
|
+
- Short, self-contained tasks
|
|
108
|
+
- Pickers and selections
|
|
109
|
+
|
|
110
|
+
**Always provide**:
|
|
111
|
+
- Clear dismiss buttons for modals
|
|
112
|
+
- Consistent back button behavior
|
|
113
|
+
- Confirmation for destructive actions
|
|
114
|
+
|
|
115
|
+
## Layout, Hierarchy, and Grouping
|
|
116
|
+
|
|
117
|
+
### Critical Rules
|
|
118
|
+
|
|
119
|
+
- Design around **content first**: prioritize the primary task and content; remove decorative UI that doesn't help comprehension
|
|
120
|
+
- Create **clear hierarchy**: one primary action per screen; secondary actions are visually subordinate
|
|
121
|
+
- Use **consistent spacing and alignment** to communicate grouping; avoid "random" padding values across the app
|
|
122
|
+
- Prefer system containers (`List`, `Form`, `Section`, `Toolbar`, `NavigationStack`) that encode platform layout conventions
|
|
123
|
+
- Avoid dense UI: keep line lengths readable and allow whitespace for scanning
|
|
124
|
+
|
|
125
|
+
### Examples
|
|
126
|
+
|
|
127
|
+
```swift
|
|
128
|
+
// ✅ Hierarchy + grouping via Sections; one primary action in toolbar
|
|
129
|
+
NavigationStack {
|
|
130
|
+
List {
|
|
131
|
+
Section("Details") {
|
|
132
|
+
TextField("Title", text: $model.title)
|
|
133
|
+
TextField("Notes", text: $model.notes, axis: .vertical)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Section("Metadata") {
|
|
137
|
+
Toggle("Pinned", isOn: $model.isPinned)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
.navigationTitle("New item")
|
|
141
|
+
.toolbar {
|
|
142
|
+
ToolbarItem(placement: .confirmationAction) {
|
|
143
|
+
Button("Save", action: model.save)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ✅ Clear visual hierarchy with system components
|
|
149
|
+
VStack(spacing: 16) {
|
|
150
|
+
// Primary action
|
|
151
|
+
Button("Continue", action: model.continue)
|
|
152
|
+
.buttonStyle(.borderedProminent)
|
|
153
|
+
.controlSize(.large)
|
|
154
|
+
|
|
155
|
+
// Secondary action
|
|
156
|
+
Button("Skip for now", action: model.skip)
|
|
157
|
+
.buttonStyle(.borderless)
|
|
158
|
+
.foregroundStyle(.secondary)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ❌ Flat wall-of-controls with unclear priority
|
|
162
|
+
VStack(spacing: 3) {
|
|
163
|
+
Text("New item").font(.title2)
|
|
164
|
+
TextField("Title", text: $model.title).padding(1)
|
|
165
|
+
TextField("Notes", text: $model.notes).padding(23)
|
|
166
|
+
Toggle("Pinned", isOn: $model.isPinned)
|
|
167
|
+
Button("Save", action: model.save)
|
|
168
|
+
Button("Delete", action: model.delete)
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Layout Guidelines
|
|
173
|
+
|
|
174
|
+
**Visual Hierarchy**:
|
|
175
|
+
- One primary action per screen (prominent button style)
|
|
176
|
+
- Secondary actions are visually subordinate (borderless, smaller)
|
|
177
|
+
- Destructive actions are clearly marked (`.destructive` role)
|
|
178
|
+
|
|
179
|
+
**Spacing and Grouping**:
|
|
180
|
+
- Use `Section` in `List` or `Form` to group related controls
|
|
181
|
+
- Consistent spacing values (8, 12, 16, 20, 24)
|
|
182
|
+
- Whitespace communicates relationships
|
|
183
|
+
|
|
184
|
+
**System Containers**:
|
|
185
|
+
- `List` for browsable content
|
|
186
|
+
- `Form` for data entry
|
|
187
|
+
- `Section` for grouping
|
|
188
|
+
- `Toolbar` for actions
|
|
189
|
+
- `NavigationStack` for hierarchies
|
|
190
|
+
|
|
191
|
+
## Summary
|
|
192
|
+
|
|
193
|
+
**Key Principles**:
|
|
194
|
+
1. Use system controls with comfortable hit targets
|
|
195
|
+
2. NavigationStack for drill-down, modals for tasks
|
|
196
|
+
3. Always provide clear dismiss paths
|
|
197
|
+
4. One primary action per screen
|
|
198
|
+
5. Use sections and spacing for grouping
|
|
199
|
+
6. Prefer system containers over custom layouts
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Performance and Platform Conventions
|
|
2
|
+
|
|
3
|
+
Apple Human Interface Guidelines for performance, responsiveness, and platform-native patterns.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Performance and Responsiveness](#performance-and-responsiveness)
|
|
7
|
+
2. [Platform Conventions](#platform-conventions)
|
|
8
|
+
|
|
9
|
+
## Performance and Responsiveness
|
|
10
|
+
|
|
11
|
+
### Critical Rules
|
|
12
|
+
|
|
13
|
+
- Optimize for **perceived performance**: show progress quickly, keep interactions responsive, and avoid blocking the main actor
|
|
14
|
+
- Use incremental loading patterns where appropriate; avoid doing heavy work during view rendering
|
|
15
|
+
- Prefer clear placeholder/progress UI over a frozen screen
|
|
16
|
+
- Avoid unnecessary animations, shadows, and effects that degrade scrolling performance
|
|
17
|
+
|
|
18
|
+
### Examples
|
|
19
|
+
|
|
20
|
+
```swift
|
|
21
|
+
// ✅ Immediate feedback and non-blocking load
|
|
22
|
+
VStack {
|
|
23
|
+
if model.isLoading {
|
|
24
|
+
ProgressView("Loading…")
|
|
25
|
+
} else {
|
|
26
|
+
List(model.items) { item in Text(item.title) }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
.task { await model.loadIfNeeded() }
|
|
30
|
+
|
|
31
|
+
// ❌ Heavy synchronous work during view body; causes jank
|
|
32
|
+
var body: some View {
|
|
33
|
+
let items = model.computeExpensiveListSynchronously()
|
|
34
|
+
return List(items) { item in Text(item.title) }
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Performance Guidelines
|
|
39
|
+
|
|
40
|
+
**Perceived Performance**:
|
|
41
|
+
- Show UI immediately, even if data isn't ready
|
|
42
|
+
- Use `ProgressView` or skeleton states while loading
|
|
43
|
+
- Keep interactions responsive (<100ms feedback)
|
|
44
|
+
- Avoid blocking the main thread
|
|
45
|
+
|
|
46
|
+
**Async Work**:
|
|
47
|
+
- Use `.task { }` for async loading in views
|
|
48
|
+
- Move heavy computation to background tasks
|
|
49
|
+
- Never do expensive work in `body` or computed properties
|
|
50
|
+
|
|
51
|
+
**Rendering Performance**:
|
|
52
|
+
- Avoid heavy shadows, blurs, or complex gradients in scrolling views
|
|
53
|
+
- Use `LazyVStack`/`LazyHStack` for large lists
|
|
54
|
+
- Profile with Instruments if scrolling feels janky
|
|
55
|
+
|
|
56
|
+
**Loading Patterns**:
|
|
57
|
+
- Show skeleton/placeholder UI immediately
|
|
58
|
+
- Load data incrementally when appropriate
|
|
59
|
+
- Provide progress indication for operations >1 second
|
|
60
|
+
|
|
61
|
+
## Platform Conventions
|
|
62
|
+
|
|
63
|
+
### Critical Rules
|
|
64
|
+
|
|
65
|
+
- Prefer system components before custom UI (Lists, Forms, toolbars, menus, context menus)
|
|
66
|
+
- Use SF Symbols consistently and pair icons with text for clarity when appropriate
|
|
67
|
+
- Keep controls and terminology consistent with iOS conventions (Done/Cancel, Back, Edit)
|
|
68
|
+
- Avoid recreating iOS UI patterns with bespoke visuals unless you have a strong UX reason
|
|
69
|
+
|
|
70
|
+
### Examples
|
|
71
|
+
|
|
72
|
+
```swift
|
|
73
|
+
// ✅ System toolbar placements and familiar labels
|
|
74
|
+
.toolbar {
|
|
75
|
+
ToolbarItem(placement: .cancellationAction) {
|
|
76
|
+
Button("Cancel", role: .cancel) { model.cancel() }
|
|
77
|
+
}
|
|
78
|
+
ToolbarItem(placement: .confirmationAction) {
|
|
79
|
+
Button("Done", action: model.done)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ❌ Custom "Close" / "Okay" in random placements; inconsistent with platform
|
|
84
|
+
.toolbar {
|
|
85
|
+
ToolbarItem(placement: .automatic) { Button("Okay") {} }
|
|
86
|
+
ToolbarItem(placement: .automatic) { Button("Close") {} }
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Platform Guidelines
|
|
91
|
+
|
|
92
|
+
**System Components**:
|
|
93
|
+
- `List` for browsable content
|
|
94
|
+
- `Form` for settings and data entry
|
|
95
|
+
- `Toolbar` for actions
|
|
96
|
+
- `NavigationStack` for hierarchical navigation
|
|
97
|
+
- `Menu` and context menus for secondary actions
|
|
98
|
+
|
|
99
|
+
**SF Symbols**:
|
|
100
|
+
- Use SF Symbols for icons (system-provided, adapts to Dynamic Type)
|
|
101
|
+
- Pair icons with text labels for clarity
|
|
102
|
+
- Use consistent symbols throughout the app
|
|
103
|
+
- Prefer standard symbols over custom icons
|
|
104
|
+
|
|
105
|
+
**Platform Terminology**:
|
|
106
|
+
- ✅ "Done", "Cancel", "Save", "Delete", "Edit"
|
|
107
|
+
- ❌ "Okay", "Close", "Submit", "Remove", "Modify"
|
|
108
|
+
|
|
109
|
+
**Standard Placements**:
|
|
110
|
+
- `.cancellationAction` - Cancel/Back (leading on modals)
|
|
111
|
+
- `.confirmationAction` - Done/Save (trailing on modals)
|
|
112
|
+
- `.destructive` role for Delete actions
|
|
113
|
+
- `.primaryAction` for main toolbar actions
|
|
114
|
+
|
|
115
|
+
**Consistency**:
|
|
116
|
+
- Follow iOS patterns for common flows (creation, editing, deletion)
|
|
117
|
+
- Use standard gestures (swipe to delete, pull to refresh)
|
|
118
|
+
- Respect system settings (Dynamic Type, Reduce Motion, Reduce Transparency)
|
|
119
|
+
|
|
120
|
+
## Summary
|
|
121
|
+
|
|
122
|
+
**Key Principles**:
|
|
123
|
+
1. Show UI immediately; load data asynchronously
|
|
124
|
+
2. Use `ProgressView` and skeleton states while loading
|
|
125
|
+
3. Avoid heavy work during view rendering
|
|
126
|
+
4. Prefer system components over custom UI
|
|
127
|
+
5. Use SF Symbols and standard terminology
|
|
128
|
+
6. Follow platform conventions for toolbar placements and actions
|
|
129
|
+
7. Keep controls and terminology consistent with iOS
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Privacy and Permissions
|
|
2
|
+
|
|
3
|
+
Apple Human Interface Guidelines for requesting permissions and handling sensitive data.
|
|
4
|
+
|
|
5
|
+
## Critical Rules
|
|
6
|
+
|
|
7
|
+
- Request permissions **in context**, right before the feature needs it—never at app launch without cause
|
|
8
|
+
- Explain **why** in user language and connect it to a clear benefit
|
|
9
|
+
- If denied, provide a functional fallback and a clear path to Settings when appropriate
|
|
10
|
+
- Minimize data collection; don't surface sensitive data in logs or UI where not needed
|
|
11
|
+
|
|
12
|
+
## Examples
|
|
13
|
+
|
|
14
|
+
### Permission Request Pattern
|
|
15
|
+
|
|
16
|
+
```swift
|
|
17
|
+
// ✅ Ask in context and handle denial gracefully
|
|
18
|
+
Button("Enable notifications") {
|
|
19
|
+
model.requestNotifications()
|
|
20
|
+
}
|
|
21
|
+
// On denial: show a non-blocking explanation + "Open Settings" action
|
|
22
|
+
|
|
23
|
+
// ❌ Permission request on launch with no context
|
|
24
|
+
struct AppStart {
|
|
25
|
+
func start() {
|
|
26
|
+
model.requestNotifications()
|
|
27
|
+
model.requestLocation()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Complete Permission Flow
|
|
33
|
+
|
|
34
|
+
```swift
|
|
35
|
+
// ✅ Full permission flow with context and fallback
|
|
36
|
+
struct NotificationSettingsView: View {
|
|
37
|
+
@State private var showingDeniedAlert = false
|
|
38
|
+
|
|
39
|
+
var body: some View {
|
|
40
|
+
VStack(spacing: 16) {
|
|
41
|
+
Text("Get notified when items are shared with you")
|
|
42
|
+
.font(.headline)
|
|
43
|
+
|
|
44
|
+
Text("Turn on notifications to stay updated when friends share links and notes.")
|
|
45
|
+
.font(.body)
|
|
46
|
+
.foregroundStyle(.secondary)
|
|
47
|
+
|
|
48
|
+
Button("Enable Notifications") {
|
|
49
|
+
Task {
|
|
50
|
+
let granted = await requestNotificationPermission()
|
|
51
|
+
if !granted {
|
|
52
|
+
showingDeniedAlert = true
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
.buttonStyle(.borderedProminent)
|
|
57
|
+
}
|
|
58
|
+
.alert("Notifications Disabled", isPresented: $showingDeniedAlert) {
|
|
59
|
+
Button("Open Settings") {
|
|
60
|
+
if let url = URL(string: UIApplication.openSettingsURLString) {
|
|
61
|
+
UIApplication.shared.open(url)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
Button("Not Now", role: .cancel) {}
|
|
65
|
+
} message: {
|
|
66
|
+
Text("To receive notifications, enable them in Settings.")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func requestNotificationPermission() async -> Bool {
|
|
71
|
+
let center = UNUserNotificationCenter.current()
|
|
72
|
+
do {
|
|
73
|
+
return try await center.requestAuthorization(options: [.alert, .sound, .badge])
|
|
74
|
+
} catch {
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Guidelines
|
|
82
|
+
|
|
83
|
+
### When to Request Permissions
|
|
84
|
+
|
|
85
|
+
**Good timing**:
|
|
86
|
+
- Right before using the feature (user taps "Add location")
|
|
87
|
+
- During feature onboarding (user enters location-based feature)
|
|
88
|
+
- When user explicitly opts in (settings toggle)
|
|
89
|
+
|
|
90
|
+
**Bad timing**:
|
|
91
|
+
- App launch before any context
|
|
92
|
+
- Background without user interaction
|
|
93
|
+
- Bundled with other unrelated requests
|
|
94
|
+
|
|
95
|
+
### How to Request Permissions
|
|
96
|
+
|
|
97
|
+
**Clear value proposition**:
|
|
98
|
+
- Explain the benefit in user terms
|
|
99
|
+
- Show what they'll gain, not what you need
|
|
100
|
+
- Use the feature's context to explain why
|
|
101
|
+
|
|
102
|
+
**Examples**:
|
|
103
|
+
- ✅ "Get notified when items are shared with you"
|
|
104
|
+
- ❌ "This app would like to send you notifications"
|
|
105
|
+
- ✅ "Save your location to remember where you found this"
|
|
106
|
+
- ❌ "Allow location access"
|
|
107
|
+
|
|
108
|
+
### Handling Denial
|
|
109
|
+
|
|
110
|
+
**Graceful fallback**:
|
|
111
|
+
- Don't block the entire feature if possible
|
|
112
|
+
- Provide alternative workflows
|
|
113
|
+
- Only show Settings path if user might want to change their mind
|
|
114
|
+
|
|
115
|
+
**Examples**:
|
|
116
|
+
- Location denied → Manual address entry
|
|
117
|
+
- Notifications denied → In-app badge/indicator
|
|
118
|
+
- Camera denied → Photo library picker
|
|
119
|
+
|
|
120
|
+
### Privacy Best Practices
|
|
121
|
+
|
|
122
|
+
**Data minimization**:
|
|
123
|
+
- Only request what you actually need
|
|
124
|
+
- Don't log sensitive data (passwords, tokens, personal info)
|
|
125
|
+
- Don't display sensitive data in UI unless necessary
|
|
126
|
+
- Clear sensitive data when no longer needed
|
|
127
|
+
|
|
128
|
+
**User control**:
|
|
129
|
+
- Provide clear settings to manage data
|
|
130
|
+
- Allow users to delete their data
|
|
131
|
+
- Respect system privacy settings
|
|
132
|
+
|
|
133
|
+
## Common Permissions
|
|
134
|
+
|
|
135
|
+
### Notifications
|
|
136
|
+
|
|
137
|
+
```swift
|
|
138
|
+
// Request with UNUserNotificationCenter
|
|
139
|
+
let granted = try await UNUserNotificationCenter.current()
|
|
140
|
+
.requestAuthorization(options: [.alert, .sound, .badge])
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**When to ask**: Before subscribing to notification topics or when user enables a notification-dependent feature
|
|
144
|
+
|
|
145
|
+
### Location
|
|
146
|
+
|
|
147
|
+
```swift
|
|
148
|
+
// Request with CLLocationManager
|
|
149
|
+
locationManager.requestWhenInUseAuthorization()
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**When to ask**: Right before adding a location-based item or enabling location features
|
|
153
|
+
|
|
154
|
+
### Photos
|
|
155
|
+
|
|
156
|
+
```swift
|
|
157
|
+
// Request with PHPhotoLibrary
|
|
158
|
+
let status = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**When to ask**: When user taps "Add photo" or similar action
|
|
162
|
+
|
|
163
|
+
### Camera
|
|
164
|
+
|
|
165
|
+
```swift
|
|
166
|
+
// Request with AVCaptureDevice
|
|
167
|
+
let granted = await AVCaptureDevice.requestAccess(for: .video)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**When to ask**: Right before showing camera interface
|
|
171
|
+
|
|
172
|
+
## Summary
|
|
173
|
+
|
|
174
|
+
**Key Principles**:
|
|
175
|
+
1. Request permissions in context, never at app launch
|
|
176
|
+
2. Explain the benefit in user terms
|
|
177
|
+
3. Handle denial gracefully with fallbacks
|
|
178
|
+
4. Provide path to Settings when appropriate
|
|
179
|
+
5. Minimize data collection and logging
|
|
180
|
+
6. Respect system privacy settings
|
|
181
|
+
7. Give users control over their data
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Visual Design
|
|
2
|
+
|
|
3
|
+
Apple Human Interface Guidelines for color, materials, and contrast.
|
|
4
|
+
|
|
5
|
+
## Critical Rules
|
|
6
|
+
|
|
7
|
+
- Prefer **semantic system styles** (`.tint`, `.secondary`, `.tertiary`, `Material`) over custom colors
|
|
8
|
+
- Support **light and dark mode**; don't rely on "always light" colors
|
|
9
|
+
- Maintain **sufficient contrast** for text and controls, including in accessibility settings
|
|
10
|
+
- Use color to **reinforce meaning**, not as the only indicator (pair with text/icons)
|
|
11
|
+
- Avoid decorative gradients/materials that reduce readability or increase visual noise
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Semantic System Styles
|
|
16
|
+
|
|
17
|
+
```swift
|
|
18
|
+
// ✅ Semantic styles that adapt automatically
|
|
19
|
+
HStack {
|
|
20
|
+
Image(systemName: "link")
|
|
21
|
+
.foregroundStyle(.tint)
|
|
22
|
+
Text("Open link")
|
|
23
|
+
.foregroundStyle(.primary)
|
|
24
|
+
Spacer()
|
|
25
|
+
Text("Optional")
|
|
26
|
+
.foregroundStyle(.secondary)
|
|
27
|
+
}
|
|
28
|
+
.padding()
|
|
29
|
+
.background(.thinMaterial)
|
|
30
|
+
.clipShape(.rect(cornerRadius: 12))
|
|
31
|
+
|
|
32
|
+
// ❌ Hard-coded colors that can break contrast in dark mode
|
|
33
|
+
HStack {
|
|
34
|
+
Text("Open link")
|
|
35
|
+
.foregroundStyle(Color.white)
|
|
36
|
+
}
|
|
37
|
+
.padding()
|
|
38
|
+
.background(Color.yellow)
|
|
39
|
+
.clipShape(.rect(cornerRadius: 12))
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Light and Dark Mode Support
|
|
43
|
+
|
|
44
|
+
```swift
|
|
45
|
+
// ✅ Adapts to light/dark mode automatically
|
|
46
|
+
VStack {
|
|
47
|
+
Text("Title")
|
|
48
|
+
.foregroundStyle(.primary)
|
|
49
|
+
Text("Subtitle")
|
|
50
|
+
.foregroundStyle(.secondary)
|
|
51
|
+
}
|
|
52
|
+
.background(.background)
|
|
53
|
+
|
|
54
|
+
// ❌ Hard-coded colors don't adapt
|
|
55
|
+
VStack {
|
|
56
|
+
Text("Title")
|
|
57
|
+
.foregroundStyle(Color.black)
|
|
58
|
+
Text("Subtitle")
|
|
59
|
+
.foregroundStyle(Color.gray)
|
|
60
|
+
}
|
|
61
|
+
.background(Color.white)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Color + Meaning
|
|
65
|
+
|
|
66
|
+
```swift
|
|
67
|
+
// ✅ Color reinforces meaning with text/icon
|
|
68
|
+
Label("Error occurred", systemImage: "exclamationmark.triangle")
|
|
69
|
+
.foregroundStyle(.red)
|
|
70
|
+
|
|
71
|
+
// ❌ Color alone conveys meaning
|
|
72
|
+
Circle()
|
|
73
|
+
.fill(Color.red)
|
|
74
|
+
.frame(width: 8, height: 8)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Summary
|
|
78
|
+
|
|
79
|
+
**Key Principles**:
|
|
80
|
+
1. Use semantic color styles (`.primary`, `.secondary`, `.tint`)
|
|
81
|
+
2. Support both light and dark appearance modes
|
|
82
|
+
3. Ensure sufficient contrast for readability
|
|
83
|
+
4. Pair color with text or icons for meaning
|
|
84
|
+
5. Use materials (`.thinMaterial`, `.regularMaterial`) for depth
|