Skip to content

Commit eed01bf

Browse files
Enable Return for onboarding proceed actions (#10464)
## What changed and why Made Return the default action for visible onboarding setup and Continue controls, including the active Second Brain flow, legacy conversational onboarding, and file-index completion. ## Product invariants affected none ## How it was verified - `xcrun swift build -c debug --package-path Desktop --scratch-path /tmp/omi-onboarding-return-build.dFb1iG` — passed. - `./scripts/swiftlint-wrapper.sh lint` — passed with 0 violations. - `./scripts/swift-format-wrapper.sh lint` on the five changed Swift files — passed. - `python3 scripts/check_desktop_test_quality.py` — passed. - Built and launched the isolated ad-hoc signed bundle `/Applications/omi-onboarding-return.app`; its automation bridge responded on port 47817. The copied profile was signed out, so onboarding could not be driven without interactive sign-in. - `xcrun swift test --package-path Desktop --scratch-path /tmp/omi-onboarding-return-build.dFb1iG --filter OnboardingFlowTests` is blocked before execution by unrelated existing test-target compilation errors in `RealtimeHubSessionHandoffPolicyTests` and `RealtimeVoiceContextSingleFlightTests`. ## Tests Added `OnboardingFlowTests.testOnboardingProceedActionsUseDefaultActionKeyboardShortcut`, a static SwiftUI wiring tripwire for every onboarding proceed action. ## Failure class (fixes) Failure-Class: none ## New guards (only when adding a check or ratchet) The regression tripwire is tied to this user-reported onboarding failure. It is not a shared primitive because it verifies a finite set of onboarding-specific controls, including dynamically shown Continue actions. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/BasedHardware/omi/pull/10464?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
2 parents d58796c + 2e12aad commit eed01bf

6 files changed

Lines changed: 73 additions & 9 deletions

File tree

desktop/macos/Desktop/Sources/FileIndexing/FileIndexingView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ struct FileIndexingView: View {
215215
.shadow(color: OmiColors.accent.opacity(0.4), radius: 16, x: 0, y: 4)
216216
}
217217
.buttonStyle(.plain)
218+
.keyboardShortcut(.defaultAction)
218219
.padding(.bottom, OmiSpacing.page)
219220
}
220221

desktop/macos/Desktop/Sources/MainWindow/SecondBrain/SBComponents.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct SBInkButton: View {
9191
var size: CGFloat = 14
9292
var horizontalPadding: CGFloat = 18
9393
var verticalPadding: CGFloat = 9
94+
var isDefaultAction = false
9495
let action: () -> Void
9596

9697
var body: some View {
@@ -105,6 +106,20 @@ struct SBInkButton: View {
105106
)
106107
}
107108
.buttonStyle(.plain)
109+
.modifier(SBDefaultActionKeyboardShortcut(enabled: isDefaultAction))
110+
}
111+
}
112+
113+
private struct SBDefaultActionKeyboardShortcut: ViewModifier {
114+
let enabled: Bool
115+
116+
@ViewBuilder
117+
func body(content: Content) -> some View {
118+
if enabled {
119+
content.keyboardShortcut(.defaultAction)
120+
} else {
121+
content
122+
}
108123
}
109124
}
110125

desktop/macos/Desktop/Sources/Onboarding/OnboardingChatView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ struct OnboardingChatView: View {
336336
.background(OmiColors.accent)
337337
.cornerRadius(OmiChrome.smallControlRadius)
338338
}
339-
.buttonStyle(.plain)
339+
.buttonStyle(.plain).keyboardShortcut(.defaultAction)
340340
.padding(.top, OmiSpacing.md)
341341
}
342342

desktop/macos/Desktop/Sources/Onboarding/SecondBrain/SBOnboardingView.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ struct SBOnboardingView: View {
219219
trustRow("YOURS") { Text("Pause me from the notch. Delete anything, forever.") }
220220
}
221221
.overlay(RoundedRectangle(cornerRadius: 13).stroke(sb.ink(.w1), lineWidth: 1))
222-
SBInkButton(title: "Set up Omi →") { model.answerPromise() }
222+
SBInkButton(title: "Set up Omi →", isDefaultAction: true) { model.answerPromise() }
223223
}
224224
}
225225

@@ -262,7 +262,7 @@ struct SBOnboardingView: View {
262262
Text(draft).geist(size: 17, weight: .medium).foregroundStyle(sb.ink)
263263
Text("· detected").geist(size: 12.5).foregroundStyle(sb.ink(.w4))
264264
}
265-
SBInkButton(title: "Continue") {
265+
SBInkButton(title: "Continue", isDefaultAction: true) {
266266
if let m = all.first(where: { $0.name.lowercased() == draft.lowercased() }) {
267267
model.pickLanguage(code: m.code, name: m.name)
268268
} else {
@@ -359,6 +359,7 @@ struct SBOnboardingView: View {
359359
.contentShape(Rectangle())
360360
}
361361
.buttonStyle(.plain)
362+
.keyboardShortcut(.defaultAction)
362363
} else {
363364
Button {
364365
if state == .ask { model.requestPerm(key) }
@@ -460,7 +461,9 @@ struct SBOnboardingView: View {
460461
// just a quiet Skip so the user is never stuck.
461462
Group {
462463
if model.shortcutPressed {
463-
SBInkButton(title: "Continue") { isTalk ? model.answerShortcutTalk() : model.answerShortcutOpen() }
464+
SBInkButton(title: "Continue", isDefaultAction: true) {
465+
isTalk ? model.answerShortcutTalk() : model.answerShortcutOpen()
466+
}
464467
} else {
465468
Button {
466469
isTalk ? model.answerShortcutTalk() : model.answerShortcutOpen()
@@ -493,7 +496,7 @@ struct SBOnboardingView: View {
493496
// that, a quiet "Skip for now" so the user doesn't blow past the live demo.
494497
Group {
495498
if model.screenDemoDone {
496-
SBInkButton(title: "Continue") { model.answerScreenDemo() }
499+
SBInkButton(title: "Continue", isDefaultAction: true) { model.answerScreenDemo() }
497500
} else {
498501
Button {
499502
model.answerScreenDemo()
@@ -522,7 +525,7 @@ struct SBOnboardingView: View {
522525
}
523526
.padding(.horizontal, 14)
524527
.overlay(RoundedRectangle(cornerRadius: 13).stroke(sb.ink(.w1), lineWidth: 1))
525-
SBInkButton(title: "Continue") { model.answerAgents() }
528+
SBInkButton(title: "Continue", isDefaultAction: true) { model.answerAgents() }
526529
}
527530
.frame(maxWidth: 380, alignment: .leading)
528531
}
@@ -544,7 +547,7 @@ struct SBOnboardingView: View {
544547
}
545548
.padding(.horizontal, 14)
546549
.overlay(RoundedRectangle(cornerRadius: 13).stroke(sb.ink(.w1), lineWidth: 1))
547-
SBInkButton(title: "Continue") { model.answerContext() }
550+
SBInkButton(title: "Continue", isDefaultAction: true) { model.answerContext() }
548551
}
549552
.frame(maxWidth: 380, alignment: .leading)
550553
}

desktop/macos/Desktop/Tests/OnboardingFlowTests.swift

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,44 @@ final class OnboardingFlowTests: XCTestCase {
387387
}
388388
}
389389

390+
/// Static tripwire: keyboard shortcut registration is a SwiftUI wiring
391+
/// contract, so assert every visible onboarding proceed action remains the
392+
/// default action without trying to synthesize AppKit key events in a unit test.
393+
func testOnboardingProceedActionsUseDefaultActionKeyboardShortcut() throws {
394+
// omi-test-quality: source-inspection -- static contract: verifies SwiftUI default-action wiring on every visible onboarding proceed control
395+
let chatSource = try desktopSourceFile("Onboarding/OnboardingChatView.swift")
396+
XCTAssertTrue(
397+
chatSource.contains("handleOnboardingComplete()\n })")
398+
&& chatSource.contains(".keyboardShortcut(.defaultAction)\n .padding(.top"),
399+
"the conversational onboarding Continue button must accept Return")
400+
401+
let fileIndexingSource = try desktopSourceFile("FileIndexing/FileIndexingView.swift")
402+
XCTAssertTrue(
403+
fileIndexingSource.contains("onComplete(totalFilesScanned)")
404+
&& fileIndexingSource.contains(".keyboardShortcut(.defaultAction)\n .padding(.bottom"),
405+
"the file-index onboarding Continue button must accept Return")
406+
407+
let secondBrainSource = try desktopSourceFile("Onboarding/SecondBrain/SBOnboardingView.swift")
408+
for title in ["Set up Omi →", "Continue"] {
409+
XCTAssertTrue(
410+
secondBrainSource.contains("SBInkButton(title: \"\\(title)\", isDefaultAction: true)"),
411+
"the second-brain \(title) action must accept Return")
412+
}
413+
XCTAssertEqual(
414+
secondBrainSource.components(separatedBy: "isDefaultAction: true").count - 1,
415+
6,
416+
"every visible second-brain proceed action must register Return")
417+
XCTAssertTrue(
418+
secondBrainSource.contains("Text(\"Continue →\")")
419+
&& secondBrainSource.contains(".keyboardShortcut(.defaultAction)\n } else {"),
420+
"the granted-permission Continue action must accept Return")
421+
422+
let componentsSource = try desktopSourceFile("MainWindow/SecondBrain/SBComponents.swift")
423+
XCTAssertTrue(
424+
componentsSource.contains("content.keyboardShortcut(.defaultAction)"),
425+
"SBInkButton must wire opted-in proceed actions to Return")
426+
}
427+
390428
// Regression: arrow navigation must be computed from persisted step state and
391429
// applied by the mounted view — the NSEvent monitor's captured view copy drops
392430
// @AppStorage writes on some macOS versions. These cover the extracted
@@ -440,11 +478,15 @@ final class OnboardingFlowTests: XCTestCase {
440478
}
441479

442480
private func onboardingSourceFile(_ name: String) throws -> String {
481+
try desktopSourceFile("Onboarding/\(name)")
482+
}
483+
484+
private func desktopSourceFile(_ relativePath: String) throws -> String {
443485
let sourceURL = URL(fileURLWithPath: #filePath)
444486
.deletingLastPathComponent()
445487
.deletingLastPathComponent()
446-
.appendingPathComponent("Sources/Onboarding")
447-
.appendingPathComponent(name)
488+
.appendingPathComponent("Sources")
489+
.appendingPathComponent(relativePath)
448490
// omi-test-quality: source-inspection -- static contract: forbids uncancellable deferred-advance patterns in step views
449491
return try String(contentsOf: sourceURL, encoding: .utf8)
450492
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"change": "Added Return-key support for onboarding Continue and setup actions"
3+
}

0 commit comments

Comments
 (0)