feat(ios): Settings username inline edit (closes #282)#311
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📝 WalkthroughWalkthroughAdds inline username editing in SettingsView with client-side validation, routes username updates through a shared PATCH settings API, applies returned UserDTO via a new AppViewModel method, and adds unit and UI tests including a UI-test conflict simulation flag. Changes
Sequence DiagramsequenceDiagram
participant User as User (SettingsView)
participant UI as SettingsView
participant Validation as UsernameValidation
participant API as APIClient
participant Server as Backend
participant VM as AppViewModel
User->>UI: open editor / type username / tap Save
UI->>Validation: isValid(candidate)
Validation-->>UI: valid / invalid
alt valid
UI->>API: updateSettings(username:)
API->>Server: PATCH /api/settings { username }
alt 200 OK
Server-->>API: UserDTO
API-->>UI: UserDTO
UI->>VM: applySettingsUser(UserDTO)
VM-->>VM: update currentUser if allowed
UI-->>User: show success
else 409 Conflict
Server-->>API: 409 "Username already taken"
API-->>UI: APIError
UI-->>User: show "Username already taken"
else other error
API-->>UI: APIError
UI-->>User: show generic error
end
else invalid
UI-->>User: show validation error
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📋 Issue PlannerBuilt with CodeRabbit's Coding Plans for faster development and fewer bugs. View plan used: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@CodeAnt-AI review |
|
CodeAnt AI is running the review. |
|
@cursor review |
|
@graphite-app re-review |
Sequence DiagramThis PR adds inline username editing on the iOS Settings screen with shared validation, sends a PATCH-style settings update for valid changes, and syncs the returned user into the app view model. sequenceDiagram
participant User
participant SettingsView
participant APIClient
participant Backend
participant AppViewModel
User->>SettingsView: Edit username and tap save
SettingsView->>SettingsView: Validate username locally
alt Username invalid
SettingsView-->>User: Show username validation error
else Username valid
SettingsView->>APIClient: Update settings with username
APIClient->>Backend: PATCH settings with username
Backend-->>APIClient: Return updated user
APIClient-->>AppViewModel: Provide updated user
AppViewModel-->>SettingsView: Update current user state
SettingsView-->>User: Show updated username and success message
end
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5496098. Configure here.
|
CodeAnt AI is reviewing your PR. |
|
CodeAnt AI finished reviewing your PR. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ios/StillPointApp/Views/SettingsView.swift`:
- Around line 84-85: Concurrent settings saves (username and visibility) can
overlap and a slower PATCH response can overwrite other fields when
appVM.applySettingsUser(updated) applies the whole UserDTO; fix by serializing
these save operations: introduce a small async serializer (e.g., an actor
SettingsUpdateActor or a TaskQueue) used by SettingsView to perform calls like
APIClient.shared.updateSettings(...) so only one update runs at a time, or
alternatively have the save helper merge the returned UserDTO into the existing
user rather than replacing it wholesale; update the calls around
updateSettings(...) and appVM.applySettingsUser(updated) (and the analogous
blocks at lines ~203-220 and ~295-300) to route through this serializer or use a
merge-on-apply method so overlapping requests cannot clobber each other.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a018b54e-5470-43d3-ac6b-e5e0cfa3a12c
📒 Files selected for processing (6)
ios/StillPointApp/ViewModels/AppViewModel.swiftios/StillPointApp/Views/SettingsView.swiftios/StillPointAppUITests/StillPointAppUITests.swiftios/StillPointShared/Sources/StillPointShared/APIClient.swiftios/StillPointShared/Sources/StillPointShared/UsernameValidation.swiftios/StillPointShared/Tests/StillPointSharedTests/UsernameValidationTests.swift
There was a problem hiding this comment.
🧹 Nitpick comments (1)
ios/StillPointAppUITests/StillPointAppUITests.swift (1)
169-257: ⚡ Quick winAdd one UI test for the Cancel path.
This suite covers save, validation, and conflict well, but the inline editor’s cancel affordance is still unexercised. A small test that edits the field, taps Cancel, and asserts the original username remains visible would close the main regression gap for this feature.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ios/StillPointAppUITests/StillPointAppUITests.swift` around lines 169 - 257, Add a new UI test (e.g., testSettingsUsernameInlineEditCancelSucceeds) that exercises the cancel path: launch the app with makeApp(seedAuthenticated: true, resetStore: true), navigate to settings via openTab(...), capture the current username from app.staticTexts["settings.usernameDisplay"], tap app.buttons["settings.usernameEditButton"], wait for app.textFields["settings.usernameField"], clearUsernameFieldForUITest(field, in: app) and type a different value, tap the cancel control (app.buttons["settings.usernameCancelButton"] or whatever the cancel identifier is), then verify app.staticTexts["settings.usernameDisplay"] still exists and its label equals the original captured username; also dismissKeyboardIfPresent(in: app) at the end.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@ios/StillPointAppUITests/StillPointAppUITests.swift`:
- Around line 169-257: Add a new UI test (e.g.,
testSettingsUsernameInlineEditCancelSucceeds) that exercises the cancel path:
launch the app with makeApp(seedAuthenticated: true, resetStore: true), navigate
to settings via openTab(...), capture the current username from
app.staticTexts["settings.usernameDisplay"], tap
app.buttons["settings.usernameEditButton"], wait for
app.textFields["settings.usernameField"], clearUsernameFieldForUITest(field, in:
app) and type a different value, tap the cancel control
(app.buttons["settings.usernameCancelButton"] or whatever the cancel identifier
is), then verify app.staticTexts["settings.usernameDisplay"] still exists and
its label equals the original captured username; also
dismissKeyboardIfPresent(in: app) at the end.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 67128edd-34d8-47aa-b1f3-3fbd92b8e34a
📒 Files selected for processing (1)
ios/StillPointAppUITests/StillPointAppUITests.swift
|
CodeAnt AI is running Incremental review |
|
CodeAnt AI Incremental review completed. |
Add UsernameValidation mirroring web rules, extend APIClient with username updates and UI-test simulation (400/409), sync currentUser from settings responses, and add UITests for save, validation, and conflict paths. Closes #282 Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Rename updateSettings(body:) parameter so it does not shadow the HTTP patch helper (fixes Swift compile on CI). Guard applySettingsUser when logged out or user id mismatches. Add deterministic UITest field clear fallback when Select All is unavailable. Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Sequence DiagramThis diagram shows how the iOS Settings screen now supports inline username editing with local validation, a PATCH settings call, and syncing the updated user back into app state. sequenceDiagram
participant User
participant SettingsView
participant APIClient
participant Backend
participant AppViewModel
User->>SettingsView: Tap Edit username and enter new value
SettingsView->>SettingsView: Validate username
SettingsView->>APIClient: Request username update
APIClient->>Backend: PATCH settings with new username
Backend-->>APIClient: Return updated user
APIClient-->>SettingsView: Updated user data
SettingsView->>AppViewModel: Apply updated user
AppViewModel-->>SettingsView: Current user state updated in UI
Generated by CodeAnt AI |
| field.tap() | ||
| field.press(forDuration: 1.2) | ||
| let selectAll = app.menuItems["Select All"] | ||
| if selectAll.waitForExistence(timeout: 2) { | ||
| selectAll.tap() | ||
| return | ||
| } | ||
| let deleteKey = app.keyboards.keys["Delete"] | ||
| XCTAssertTrue( | ||
| deleteKey.waitForExistence(timeout: 3), | ||
| "Expected keyboard with Delete after focusing username field" | ||
| ) | ||
| for _ in 0..<40 { | ||
| deleteKey.tap() |
There was a problem hiding this comment.
Suggestion: The delete-key fallback assumes the cursor is positioned at the end of the text, but after long-press focus that is not guaranteed. If the caret is in the middle/start, repeated Delete taps will not fully clear the username, so new text can be inserted into leftover content and make username assertions flaky. Ensure full selection before deletion or verify the field is empty after clearing. [possible bug]
Severity Level: Major ⚠️
- ⚠️ Settings username success UITest can intermittently fail in CI.
- ⚠️ Username validation error UITest susceptible to inconsistent input state.
- ⚠️ Username conflict UITest may assert against unintended concatenated usernames.Steps of Reproduction ✅
1. Run `testSettingsUsernameInlineEditSucceeds()` in
`ios/StillPointAppUITests/StillPointAppUITests.swift:173-199`, which opens Settings from
Home (lines 178-179) and focuses the username input `settings.usernameField` (lines
185-186).
2. At line 187, the test calls `clearUsernameFieldForUITest(field, in: app)`, whose
implementation at lines 590-607 is intended to clear the existing username before typing a
new one; the helper comment explicitly notes the "Select All" context menu is flaky in CI.
3. Inside `clearUsernameFieldForUITest`, the field is tapped and long-pressed (lines
592-593). If the `"Select All"` menu item does **not** appear within 2 seconds (the
fallback case at lines 594-598), the helper asserts the keyboard delete key exists (lines
599-603) and then taps Delete 40 times (lines 604-605).
4. Because the tap and long-press are performed at the element's default/center
coordinate, the text cursor can be positioned in the middle of the existing username
string; repeated Delete keypresses only delete characters to the **left** of the caret,
leaving any characters to the right intact. After this fallback, when the test resumes and
calls `field.typeText("fixture_renamed")` at line 188, the new text is inserted before the
leftover suffix, so the final field value may be e.g. `"userfixture_renamed"` instead of
`"fixture_renamed"`. The subsequent save at lines 190-192 and assertion
`XCTAssertEqual(display.label, "fixture_renamed")` at line 196 will then fail, even though
the helper claimed to "clear" the field.
5. The same helper is used in `testSettingsUsernameValidationError()` (lines 201-230) and
`testSettingsUsernameConflictShowsTakenMessage()` (lines 232-261) via calls at lines 215
and 246 respectively, so the incomplete-clearing behavior in the fallback path can also
cause inconsistent inputs and flakiness in the validation-error and conflict-message
UITests whenever the `"Select All"` menu fails to appear.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** ios/StillPointAppUITests/StillPointAppUITests.swift
**Line:** 592:605
**Comment:**
*Possible Bug: The delete-key fallback assumes the cursor is positioned at the end of the text, but after long-press focus that is not guaranteed. If the caret is in the middle/start, repeated Delete taps will not fully clear the username, so new text can be inserted into leftover content and make username assertions flaky. Ensure full selection before deletion or verify the field is empty after clearing.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR lets users edit their username directly in the iOS Settings screen, validates it locally, sends a PATCH to update settings, and syncs the returned user into app state so the new username is shown immediately. sequenceDiagram
participant User
participant SettingsView
participant APIClient
participant Backend
participant AppState
User->>SettingsView: Edit username and tap Save
SettingsView->>SettingsView: Validate username and prepare trimmed value
SettingsView->>APIClient: Update settings with new username
APIClient->>Backend: PATCH settings username
Backend-->>APIClient: Return updated user
APIClient-->>SettingsView: Updated user data
SettingsView->>AppState: Apply updated user to current user
AppState-->>SettingsView: Updated username reflected in Settings view
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis PR lets users edit their username inline in iOS Settings, validates it before sending, and uses a shared PATCH settings flow that returns an updated user and synchronizes app state. sequenceDiagram
participant User
participant SettingsView
participant AppViewModel
participant APIClient
participant SettingsAPI
User->>SettingsView: Change username or visibility
SettingsView->>SettingsView: Validate input and mark settings as saving
SettingsView->>APIClient: Request settings update
APIClient->>SettingsAPI: PATCH settings with partial body
SettingsAPI-->>APIClient: Updated user data
APIClient-->>AppViewModel: Return updated user
AppViewModel-->>SettingsView: Apply settings user and refresh UI state
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis diagram shows how the iOS Settings screen now supports inline username editing with local validation, a settings PATCH call, and immediate UI update from the returned user data. sequenceDiagram
participant User
participant SettingsView
participant Backend
User->>SettingsView: Open Settings and tap Edit username
SettingsView->>SettingsView: Capture new username and validate
User->>SettingsView: Tap Save username
SettingsView->>Backend: Send settings update with new username
Backend-->>SettingsView: Return updated user data
SettingsView->>SettingsView: Update local user and show new username
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis diagram shows how the iOS Settings screen validates a new username, calls the shared settings API to update it, and syncs the updated user back into app state, including handling local validation errors. sequenceDiagram
participant User
participant Settings as Settings screen
participant API as API client
participant Server as Backend
participant AppVM as App view model
User->>Settings: Edit username and tap Save
Settings->>Settings: Validate username
alt Invalid username
Settings-->>User: Show validation error
else Valid username
Settings->>API: Update settings username
API->>Server: Patch settings with new username
Server-->>API: Updated user
API-->>Settings: Updated user
Settings->>AppVM: Apply updated user
AppVM-->>Settings: Updated current user state
Settings-->>User: Show updated username and success message
end
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
|
CodeAnt AI is running the review. |
Sequence DiagramThis diagram shows how the iOS Settings screen now handles inline username edits (and visibility changes), validating input, sending a single settings update, and syncing the updated user back into app state. sequenceDiagram
participant User
participant SettingsView
participant APIClient
participant Backend
participant AppViewModel
User->>SettingsView: Change username or visibility and tap Save
SettingsView->>SettingsView: Validate input and ensure single active save
Note over SettingsView: Skip new saves while another settings update is in progress
SettingsView->>APIClient: Send settings patch
APIClient->>Backend: Patch settings with new values
Backend-->>APIClient: Return updated user data
APIClient-->>SettingsView: Updated user
SettingsView->>AppViewModel: applySettingsUser with updated user
AppViewModel-->>SettingsView: Update current user and refresh settings display
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. |
User description
Summary
Ports web-style username editing to iOS Settings (inline edit, validation, PATCH, local user sync).
Babysitter follow-ups
updateSettingsparameter frompatchtobodyto avoid shadowing the HTTPpatchmethod.applySettingsUserguarded when logged out / user id mismatch.Closes #282
CodeAnt-AI Description
Add inline username editing in iOS Settings with validation and save feedback
What Changed
Impact
✅ Shorter username changes✅ Clearer username error messages✅ Fewer Settings update conflicts🔄 Retrigger CodeAnt AI Review
Details
💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.