uttrflow / uttrflow/uttrflow-swift

Onboarding's permission pages have no way past a refusal, and the Accessibility page opens with its "cannot go on" warning before asking

Open
#669 0 comments 0 reactions 0 assignees View on GitHub
area:general bug needs-info P1
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

`Docs/ux-onboarding.md` states the rule onboarding is built on: "No page is a dead end. Whatever the user has refused, there is always a control that moves them on, and what refusing cost them is said plainly on the last page."

The two permission pages break it, and the Accessibility page also opens in its refused state before anything has been asked.

**Accessibility is never "not determined".** `AccessibilityPermissionGate` reads `AXIsProcessTrusted() ? .granted : .denied` (`Sources/UttrflowPermissions/AccessibilityPermissionGate+System.swift:15`). So on first entry the page is `.permission(.denied)`, and `OnboardingPresenter`:

- offers only "Open System Settings" (`Sources/UttrflowUX/OnboardingPresenter.swift:307-308`); the "Allow Accessibility Access" button for `.notDetermined` (`:305-306`) is unreachable for this page;
- shows the warning note at once, because the note is suppressed only for `.notDetermined` (`:155-162`): "Until this is on, Uttrflow has nowhere to put your words: it cannot type into another app, and setting up cannot go on without it." (`:410-413`). The comment on that function says the note is "shown only once the user has been asked".

**Neither permission page can be left without granting.** For `.denied` the only button opens System Settings; after that, `.awaitingSystemSettings` offers "Open System Settings" and "Check Again" (`:309-311`). "Continue Without It" exists only for `.restricted` (`:312-314`). The window's only other exit is its close button, which does not finish onboarding (see `OnboardingWindowController.onFinish`, "never for a window simply shut"), so the flow reopens on every launch.

The last page already has endings for exactly these refusals, `.pastesManually` ("You're set, with one catch … Turn on Accessibility whenever you like", `:231-247`) and `.needsMicrophone` (`:264-279`), and the main app works without Accessibility by putting the words on the clipboard. Through the normal flow those endings are reached only if a permission is revoked between pages.

## Why it matters

- A first-run user who does not want to grant Accessibility (a common and reasonable choice on a work Mac) cannot finish setting up, even though the app supports that mode and the last page describes it.
- The first thing the Accessibility page says, before the user has done anything, is a warning that setup cannot continue.
- A VoiceOver user hears the warning as the page's first note, before any explanation of what to press.

## How to reproduce

1. `tccutil reset Accessibility` for the dev bundle and delete the onboarding record (`defaults delete` the `com.uttrflow.onboarding.v1` key in the app's domain).
2. Launch and continue to the Accessibility page: there is no Allow button and the warning is already showing.
3. Try to reach the last page without turning Accessibility on. There is no control that does it.

Or read `OnboardingPresenterTests` (`Tests/UttrflowUXTests/OnboardingPresenterTests.swift:224-226`), which pins "Open System Settings" as the only answer to a denied Accessibility page.

## Acceptance criteria

Product decision first (hence `needs-info`): may a user finish onboarding without Accessibility, without the microphone, or both?

If yes (which is what `Docs/ux-onboarding.md` says today):

- Both permission pages offer a plain "Continue Without It" (or similar) beside the prominent grant button in the `.denied` and `.awaitingSystemSettings` states, and the last page shows the matching ending.
- The Accessibility page's first visit does not show the refusal warning; it is shown only after the user has been to System Settings and come back without granting.
- The warning text no longer says setup cannot go on.
- `OnboardingFlowTests` covers finishing with each permission refused and reaching `.pastesManually` / `.needsMicrophone`.

If no: update `Docs/ux-onboarding.md` to say which pages are gates, and still fix the first-visit warning.

Contributor guide

Open the contributing guide

Research direction

Start with Docs/ux-onboarding.md and the cited AccessibilityPermissionGate+System.swift and OnboardingPresenter.swift states, then read OnboardingPresenterTests.swift and OnboardingFlowTests. Resolve whether onboarding may finish without Accessibility or the microphone; done means the documented decision is implemented, first-visit warning behavior is corrected, and refused-permission flows reach the matching final-page ending.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
accessibility, desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.