Skip to content

fix: sync onboarding hotkey mode immediately - #133

Merged
jatinkrmalik merged 3 commits into
VocaHQ:mainfrom
d1scolor:fix-setup-toggle-mode-sync
Jun 2, 2026
Merged

fix: sync onboarding hotkey mode immediately#133
jatinkrmalik merged 3 commits into
VocaHQ:mainfrom
d1scolor:fix-setup-toggle-mode-sync

Conversation

@d1scolor

@d1scolor d1scolor commented May 8, 2026

Copy link
Copy Markdown
Contributor

The setup wizard saved activation mode changes through @AppStorage, but the global hotkey listener could already be running with the default push-to-talk configuration. That left first-time users in a confusing state where double-tap was saved in preferences while the live event tap still behaved as press-to-talk until the app restarted.

Add AppState.syncHotKeyConfiguration() as the shared path for applying persisted hotkey settings to the active HotKeyManager. Onboarding now refreshes the live listener when activation mode, hotkey, or double-tap threshold changes, and completeOnboarding() applies the current configuration again before marking setup complete. Settings now uses the same sync path, including max recording duration so the safety timeout remains aligned.

Tests extend the hotkey mock to record configuration updates and cover both direct sync and onboarding completion sync. Local verification: swift test was attempted; the sandboxed run could not write SwiftPM caches, the escalated debug run was blocked by the existing SwiftUI #Preview macro/PreviewsMacros command-line toolchain issue, and the release test run was blocked by local XCTest availability. Manual app testing confirmed the setup wizard hotkey mode issue is fixed.

jatinkrmalik

This comment was marked as duplicate.

@jatinkrmalik jatinkrmalik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@d1scolor Nice fix, the bug is real and centralising the sync path is the right shape. A few inline nits, nothing blocking.

Comment thread Sources/VocaMac/Models/AppState.swift
Comment thread Sources/VocaMac/Models/AppState.swift Outdated
Comment thread Sources/VocaMac/Models/AppState.swift
Comment thread Sources/VocaMac/Views/OnboardingView.swift
Comment thread Sources/VocaMac/Views/SettingsView.swift Outdated
Comment thread Sources/VocaMac/Views/SettingsView.swift
Comment thread Tests/VocaMacTests/Mocks/MockServices.swift
Comment thread Tests/VocaMacTests/AppStateTests.swift
@d1scolor

Copy link
Copy Markdown
Contributor Author

@jatinkrmalik thanks for the feedback, all addressed.

@jatinkrmalik jatinkrmalik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@d1scolor Approved with one safety nit.

The shared syncHotKeyConfiguration() path is the right shape for keeping onboarding, settings, and startup aligned, and the test additions cover the important configuration tuple.

I left one inline comment on resetting hotkey key state during onboarding completion while a recording may still be active.

Comment thread Sources/VocaMac/Models/AppState.swift Outdated
d1scolor added 3 commits June 2, 2026 11:37
The setup wizard saved activation mode changes through @AppStorage, but the global hotkey listener could already be running with the default push-to-talk configuration. That left first-time users in a confusing state where double-tap was saved in preferences while the live event tap still behaved as press-to-talk until the app restarted.

Add AppState.syncHotKeyConfiguration() as the shared path for applying persisted hotkey settings to the active HotKeyManager. Onboarding now refreshes the live listener when activation mode, hotkey, or double-tap threshold changes, and completeOnboarding() applies the current configuration again before marking setup complete. Settings now uses the same sync path, including max recording duration so the safety timeout remains aligned.

Tests extend the hotkey mock to record configuration updates and cover both direct sync and onboarding completion sync. Local verification: swift test was attempted; the sandboxed run could not write SwiftPM caches, the escalated debug run was blocked by the existing SwiftUI #Preview macro/PreviewsMacros command-line toolchain issue, and the release test run was blocked by local XCTest availability. Manual app testing confirmed the setup wizard hotkey mode issue is fixed.
The PR review called out a few places where the hotkey listener sync path could drift or create avoidable noise. This follow-up keeps the live listener updates focused while preserving the immediate onboarding behavior the original fix introduced.

Centralize the hotkey safety timeout calculation so startup, permission-grant startup, and explicit syncs all use the same max-recording-duration slack. Demote the sync log to debug, sync double-tap threshold sliders only when editing commits, and document that onboarding's live onChange handlers cover only the fields shown in that step.

Also reset the hotkey key-state when onboarding completes, and extend AppState tests to cover the default sync tuple plus the completion reset. Caveat: the first sandboxed swift test run could not write SwiftPM/Clang caches; the escalated run completed successfully.

Verification: swift test (171 tests, 0 failures).
Completing onboarding syncs the latest hotkey configuration and then clears stale key state, but resetting key state while a recording is active can cancel the push-to-talk safety timer. That creates a narrow path where a held-key release could be ignored and the safety backstop would be unavailable until the audio engine max-duration callback fires.

Keep the configuration sync on completion, but only reset hotkey key state when AppState is not recording. Add onboarding coverage that locks in the active-recording behavior so the hotkey reset path cannot regress silently.

Verification: swift test --filter AppStateOnboardingTests; swift test.

@jatinkrmalik jatinkrmalik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall assessment: merge-ready from my review. I rebased the branch onto current origin/main (9b76574) and pushed the new head 9169492 with --force-with-lease. Re-fix check: I found related prior work around custom hotkeys, onboarding, and max-recording safety timers, but I did not find an earlier fix for this specific first-run onboarding live-listener sync issue. Local verification passed with swift test --filter AppStateOnboardingTests (8 tests, 0 failures) and swift test (176 tests, 1 skipped for local Accessibility permission, 0 failures). GitHub currently reports the PR as mergeable, with no checks reported on the branch and review still required.

/// Apply persisted hotkey settings to the active listener.
/// `@AppStorage` updates save preferences immediately, but an already-running
/// event tap also needs its in-memory configuration refreshed.
func syncHotKeyConfiguration() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syncHotKeyConfiguration() is the right shared entry point here. It keeps onboarding, settings, startup, and permission-grant behavior aligned without pushing more HotKeyManager details into the views.

}

@MainActor
func testCompleteOnboardingSyncsHotKeyConfiguration() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good coverage for the original drift: persisted hotkey settings now have an explicit assertion that they are applied to the live listener during onboarding completion.

@jatinkrmalik
jatinkrmalik merged commit ea386a8 into VocaHQ:main Jun 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants