Skip to content

Commit 6840d6c

Browse files
committed
Fix App Store review issues (5.1.1, 5.2.5, 2.1)
- Remove skip button from onboarding flow (Guideline 5.1.1) - Enhance Apple Weather attribution visibility (Guideline 5.2.5) - Add loading state to ToolSettingsView to prevent errors (Guideline 2.1)
1 parent fac1e67 commit 6840d6c

File tree

3 files changed

+88
-91
lines changed

3 files changed

+88
-91
lines changed

apple/Clarissa/Sources/UI/OnboardingView.swift

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ public struct OnboardingView: View {
139139

140140
// MARK: - Glass Buttons Section (iOS/macOS 26+)
141141

142+
// MARK: - Glass Buttons Section (iOS/macOS 26+)
143+
// Skip button removed entirely per App Store guideline 5.1.1
144+
// Users must proceed through all onboarding pages including permissions
145+
142146
@available(iOS 26.0, macOS 26.0, *)
143147
private var glassButtonsSection: some View {
144148
GlassEffectContainer(spacing: 20) {
@@ -149,11 +153,6 @@ public struct OnboardingView: View {
149153
} else {
150154
continueButton
151155
.glassEffectID("primaryButton", in: onboardingNamespace)
152-
153-
// Hide skip on permissions page per App Store guideline 5.1.1
154-
if !pages[currentPage].isPermissionsPage {
155-
skipButton
156-
}
157156
}
158157
}
159158
.padding(.horizontal, 24)
@@ -169,33 +168,12 @@ public struct OnboardingView: View {
169168
getStartedButton
170169
} else {
171170
continueButton
172-
173-
// Hide skip on permissions page per App Store guideline 5.1.1
174-
if !pages[currentPage].isPermissionsPage {
175-
skipButton
176-
}
177171
}
178172
}
179173
.padding(.horizontal, 24)
180174
.padding(.bottom, 32)
181175
}
182176

183-
// MARK: - Skip Button
184-
185-
private var skipButton: some View {
186-
Button {
187-
HapticManager.shared.lightTap()
188-
appState.completeOnboarding()
189-
} label: {
190-
Text("Skip")
191-
.font(.subheadline)
192-
.foregroundStyle(.secondary)
193-
}
194-
.buttonStyle(.plain)
195-
.accessibilityLabel("Skip")
196-
.accessibilityHint("Double-tap to skip onboarding and start using Clarissa")
197-
}
198-
199177
// MARK: - Button Components with Glass Effects
200178

201179
@ViewBuilder

apple/Clarissa/Sources/UI/ToolResultViews.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,17 @@ struct WeatherResultView: View {
161161
}
162162

163163
// Apple Weather attribution (required by WeatherKit per App Store guideline 5.2.5)
164+
// Must display Apple Weather trademark and legal attribution link
164165
Link(destination: URL(string: "https://weatherkit.apple.com/legal-attribution.html")!) {
165-
HStack(spacing: 2) {
166-
// Use Apple logo character (\u{F8FF}) for proper trademark display
167-
Text("\u{F8FF} Weather")
168-
.font(.caption2)
166+
HStack(spacing: 4) {
167+
Image(systemName: "apple.logo")
168+
.font(.caption)
169+
Text("Weather")
170+
.font(.caption.weight(.medium))
169171
}
170172
.foregroundStyle(.secondary)
171173
}
172-
.accessibilityLabel("Apple Weather. Tap for legal attribution.")
174+
.accessibilityLabel("Data provided by Apple Weather. Tap for legal attribution.")
173175
}
174176
.accessibilityElement(children: .contain)
175177
}

apple/Clarissa/Sources/UI/ToolSettingsView.swift

Lines changed: 77 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct ToolSettingsView: View {
66
@State private var tools: [ToolInfo] = []
77
@State private var enabledCount: Int = 0
88
@State private var isAtLimit: Bool = false
9+
@State private var isLoaded: Bool = false
910
let onDismiss: (() -> Void)?
1011

1112
init(onDismiss: (() -> Void)? = nil) {
@@ -44,38 +45,43 @@ struct ToolSettingsView: View {
4445

4546
Divider()
4647

47-
// Tools list
48-
List {
49-
Section {
50-
ForEach(tools) { tool in
51-
ToolRow(
52-
tool: tool,
53-
isAtLimit: isFoundationModels && isAtLimit,
54-
onToggle: {
55-
ToolSettings.shared.toggleTool(tool.id)
56-
refreshTools()
57-
}
58-
)
59-
}
60-
} header: {
61-
if isFoundationModels {
62-
Text("Enabled: \(enabledCount)/\(maxToolsForFoundationModels)")
63-
} else {
64-
Text("Built-in Tools")
65-
}
66-
} footer: {
67-
if isFoundationModels {
68-
Text("Apple Intelligence works best with \(maxToolsForFoundationModels) or fewer tools.")
69-
} else {
70-
Text("Select which tools the assistant can use.")
48+
// Tools list with loading state
49+
if isLoaded && !tools.isEmpty {
50+
List {
51+
Section {
52+
ForEach(tools) { tool in
53+
ToolRow(
54+
tool: tool,
55+
isAtLimit: isFoundationModels && isAtLimit,
56+
onToggle: {
57+
ToolSettings.shared.toggleTool(tool.id)
58+
refreshTools()
59+
}
60+
)
61+
}
62+
} header: {
63+
if isFoundationModels {
64+
Text("Enabled: \(enabledCount)/\(maxToolsForFoundationModels)")
65+
} else {
66+
Text("Built-in Tools")
67+
}
68+
} footer: {
69+
if isFoundationModels {
70+
Text("Apple Intelligence works best with \(maxToolsForFoundationModels) or fewer tools.")
71+
} else {
72+
Text("Select which tools the assistant can use.")
73+
}
7174
}
72-
}
7375

74-
Section {
75-
customToolsComingSoon
76-
} header: {
77-
Text("Custom Tools")
76+
Section {
77+
customToolsComingSoon
78+
} header: {
79+
Text("Custom Tools")
80+
}
7881
}
82+
} else {
83+
ProgressView("Loading tools...")
84+
.frame(maxWidth: .infinity, maxHeight: .infinity)
7985
}
8086
}
8187
.frame(minWidth: 400, minHeight: 400)
@@ -112,36 +118,44 @@ struct ToolSettingsView: View {
112118
}
113119

114120
private var toolsList: some View {
115-
List {
116-
Section {
117-
ForEach(tools) { tool in
118-
ToolRow(
119-
tool: tool,
120-
isAtLimit: isFoundationModels && isAtLimit,
121-
onToggle: {
122-
ToolSettings.shared.toggleTool(tool.id)
123-
refreshTools()
121+
Group {
122+
if isLoaded && !tools.isEmpty {
123+
List {
124+
Section {
125+
ForEach(tools) { tool in
126+
ToolRow(
127+
tool: tool,
128+
isAtLimit: isFoundationModels && isAtLimit,
129+
onToggle: {
130+
ToolSettings.shared.toggleTool(tool.id)
131+
refreshTools()
132+
}
133+
)
124134
}
125-
)
126-
}
127-
} header: {
128-
if isFoundationModels {
129-
Text("Enabled: \(enabledCount)/\(maxToolsForFoundationModels)")
130-
} else {
131-
Text("Built-in Tools")
132-
}
133-
} footer: {
134-
if isFoundationModels {
135-
Text("Apple Intelligence works best with \(maxToolsForFoundationModels) or fewer tools.")
136-
} else {
137-
Text("Select which tools the assistant can use.")
138-
}
139-
}
135+
} header: {
136+
if isFoundationModels {
137+
Text("Enabled: \(enabledCount)/\(maxToolsForFoundationModels)")
138+
} else {
139+
Text("Built-in Tools")
140+
}
141+
} footer: {
142+
if isFoundationModels {
143+
Text("Apple Intelligence works best with \(maxToolsForFoundationModels) or fewer tools.")
144+
} else {
145+
Text("Select which tools the assistant can use.")
146+
}
147+
}
140148

141-
Section {
142-
customToolsComingSoon
143-
} header: {
144-
Text("Custom Tools")
149+
Section {
150+
customToolsComingSoon
151+
} header: {
152+
Text("Custom Tools")
153+
}
154+
}
155+
} else {
156+
// Loading state to prevent empty list flash
157+
ProgressView("Loading tools...")
158+
.frame(maxWidth: .infinity, maxHeight: .infinity)
145159
}
146160
}
147161
.navigationTitle("Tools")
@@ -151,9 +165,12 @@ struct ToolSettingsView: View {
151165

152166
@MainActor
153167
private func refreshTools() {
154-
tools = ToolSettings.shared.allTools
155-
enabledCount = ToolSettings.shared.enabledCount
156-
isAtLimit = ToolSettings.shared.isAtFoundationModelsLimit
168+
// Defensive loading of tool settings to prevent crashes
169+
let settings = ToolSettings.shared
170+
tools = settings.allTools
171+
enabledCount = settings.enabledCount
172+
isAtLimit = settings.isAtFoundationModelsLimit
173+
isLoaded = true
157174
}
158175

159176
@ViewBuilder

0 commit comments

Comments
 (0)