Skip to content

feat(onboarding): replace Custom tier card with a "Set up later" button#650

Merged
FuJacob merged 2 commits into
mainfrom
feat/onboarding-set-up-later
Jun 9, 2026
Merged

feat(onboarding): replace Custom tier card with a "Set up later" button#650
FuJacob merged 2 commits into
mainfrom
feat/onboarding-set-up-later

Conversation

@FuJacob

@FuJacob FuJacob commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

The onboarding "Choose a starting point" step listed Custom as a fourth tier card, but for a new user it resolved to the same plan as Everyday; its only real job was "let me move forward without committing to a curated tier." That made it a redundant card that added scrolling and a heavier-feeling choice. This removes the Custom card and folds its behavior into the footer: when no tier is selected, the primary button reads "Set up later" and applies the Custom path under the hood before advancing, so it's easier to keep moving through onboarding.

Validation

swiftlint lint --quiet Cotabby/UI/WelcomeView.swift Cotabby/UI/WelcomeTemplateStepView.swift Cotabby/Models/OnboardingTemplate.swift
# exit 0

xcodebuild -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' build -derivedDataPath build/DerivedData
# ** BUILD SUCCEEDED **

xcodebuild test -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' -derivedDataPath build/DerivedData \
  -only-testing:CotabbyTests/OnboardingTemplateRecommenderTests \
  -only-testing:CotabbyTests/OnboardingTemplateFeatureListTests CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO
# ** TEST SUCCEEDED **  16 tests, 0 failures

Not screenshotted end-to-end: reaching the template step at runtime requires granting real macOS permissions on the prior step, which isn't practical in this environment. Manual repro for a reviewer: reset onboarding, advance to Step 2 of 4, and confirm (1) only Quick / Everyday / Powerful cards render, (2) with nothing selected the footer button says "Set up later" and is enabled, and (3) selecting a tier flips it back to "Continue" with the existing download gating.

Linked issues

None.

Risk / rollout notes

  • Touches the first-run onboarding flow. Behavior changes:
    • No tier selected + "Set up later" now applies .custom and advances, instead of leaving "Continue" disabled. This is the same settings bundle the old Custom card produced (lean defaults; on the Open Source engine it downloads the balanced default model in the background, exactly as the Custom card did).
    • Returning users are unchanged: the .custom path still early-returns and preserves their tuned engine/model/behavior settings.
  • The OnboardingTemplate.custom enum case is intentionally retained (now applied implicitly, not shown as a card), so OnboardingTemplateRecommender and its tests keep full coverage over every tier.
  • No schema, settings, or pbxproj migrations. Only files under Cotabby/ (auto-discovered), so no project.yml / XcodeGen change.

Greptile Summary

This PR removes the Custom tier card from the onboarding template step and replaces its role with a "Set up later" footer button. When no curated tier is selected the primary button shows "Set up later" and is always enabled; tapping it applies the .custom path under the hood before advancing — a new user on the Open Source engine gets the same balanced default model download the Custom card used to trigger, and a returning user's existing settings are preserved unchanged.

  • OnboardingTemplate.curatedTiers is added as a static let containing only the three shown cards; .custom is intentionally kept in allCases/CaseIterable so the recommender and its tests continue to cover every tier.
  • canContinueFromTemplate now returns true when selectedTemplate == nil, WelcomeNavigation gains a continueTitle defaulting to "Continue", and the onContinue closure calls applyTemplate(.custom) only when nothing was selected before stepping forward.

Confidence Score: 5/5

Safe to merge — the change only touches first-run onboarding UI and applies the pre-existing Custom path implicitly.

All three paths through the template step (new user on Apple Intelligence, new user on Open Source, returning user) are handled correctly. The applyTemplate(.custom) call for a new Open Source user starts the same model download the old Custom card triggered; the returning-user early-return in applyTemplate preserves existing settings unchanged. curatedTiers is correctly a static let excluding .custom, while allCases/CaseIterable still cover the full enum for recommender tests. No schema, settings, or migration changes are involved.

No files require special attention.

Important Files Changed

Filename Overview
Cotabby/Models/OnboardingTemplate.swift Adds curatedTiers as a static let listing only Quick/Everyday/Powerful; .custom is retained in allCases for recommender coverage. Updated doc comment accurately describes the new UX contract.
Cotabby/UI/WelcomeTemplateStepView.swift Single-line change: allCasescuratedTiers in the ForEach that renders tier cards, correctly hiding the Custom card while keeping all other card logic unchanged.
Cotabby/UI/WelcomeView.swift Core logic changes: canContinueFromTemplate returns true for the nil-template case, continueTitle toggles between "Set up later" and "Continue", and onContinue calls applyTemplate(.custom) before advancing when nothing was selected. Returning-user early-return in applyTemplate keeps preservation behavior intact.

Comments Outside Diff (1)

  1. Cotabby/UI/WelcomeTemplateStepView.swift, line 28-29 (link)

    P2 Subtitle copy still implies selection is mandatory

    "Pick one to get set up." now contradicts the new UX — the footer button actively invites users to skip choosing a card. A first-run user will read this subtitle, feel obligated to pick, then be confused by the "Set up later" option. Something like "Pick one, or tap \"Set up later\" to configure in Settings." or simply dropping the imperative would align copy with intent.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Codex Fix in Claude Code

Reviews (2): Last reviewed commit: "refactor(onboarding): make curatedTiers ..." | Re-trigger Greptile

The starting-point step listed Custom as a fourth tier card, but for new
users it resolved to the same plan as Everyday and its real purpose was
just "let me move on without committing to a curated tier." Surfacing that
as a full card added scrolling and a redundant choice.

Drop the Custom card (render only `OnboardingTemplate.curatedTiers`) and
fold its behavior into the footer: when no tier is selected the primary
button reads "Set up later" and applies `.custom` under the hood before
advancing. With a tier selected it stays "Continue" with the existing
download gating. The `.custom` case is unchanged, so returning users still
keep their tuned settings and the recommender stays fully covered by tests.
Comment thread Cotabby/Models/OnboardingTemplate.swift Outdated
Addresses Greptile feedback: the array is constant, so a stored static let
avoids re-allocating it on every access and signals immutability.
@FuJacob FuJacob merged commit 992c1d6 into main Jun 9, 2026
4 checks passed
@FuJacob FuJacob deleted the feat/onboarding-set-up-later branch June 9, 2026 07:11
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.

1 participant