Repository navigation
ios: card replies name the task, stay under gate coaching, and lock after a new card #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: t3/ios-mvf
Are you sure you want to change the base?
Changes from all commits
a4b8b27
722df5f
98d96ca
99d4414
038f7ce
fd8f9b3
3fb1c53
4183f61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -121,14 +121,6 @@ struct WallWalkScreen: View { | |
| return .walking | ||
| } | ||
|
|
||
| /// True while the guidance points at a particular stretch the homeowner might not reach. | ||
| private var asksForArea: Bool { | ||
| switch state.guidance { | ||
| case .walk, .aimAtGround, .aimAtWall, .tiltUp, .markNextWall, .seeBehind: true | ||
| default: false | ||
| } | ||
| } | ||
|
|
||
| /// The end preview shows only with the buttons that set it: not over a question, a mark or | ||
| /// the feature tray. | ||
| private var showsEndPreview: Bool { | ||
|
|
@@ -170,7 +162,7 @@ struct WallWalkScreen: View { | |
| } | ||
| .transition(.opacity) | ||
| case .endQuestion: | ||
| // One question, two equal full-width answers that say what they mean (checklist I4). | ||
| // One question, three equal full-width answers that say what they mean (checklist I4). | ||
| VStack(spacing: 8) { | ||
| Button { | ||
| actions.answerWallEnd(turnsCorner: true) | ||
|
|
@@ -189,6 +181,18 @@ struct WallWalkScreen: View { | |
| .buttonStyle(.secondaryProminent) | ||
| .accessibilityHint("A fence, gate, or your neighbor's yard") | ||
| .accessibilityIdentifier("action.endBlocked") | ||
| // A garden wall or a fence can just stop, with no corner and nothing in the way, | ||
| // and neither answer above fits it (#70). Ends the wall as "Something blocks it" | ||
| // does: the usable wall stops here. | ||
| Button { | ||
| actions.answerWallEnd(turnsCorner: false) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When someone chooses “The wall just ends,” this button calls the same Prompt To Fix With AIThis is a comment left during a code review.
Path: ios/HouseScan/UI/Screens/WallWalkScreen.swift
Line: 188
Comment:
**Wall ending recorded as blocked**
When someone chooses “The wall just ends,” this button calls the same `answerWallEnd(turnsCorner: false)` path as “Something blocks it.” That path records a `.limit` end, which the engine defines as a wall blocked by a fence, gate, or property line. The exported scan therefore records a wall that simply stops as an obstructed wall, losing the distinction this new answer asks the homeowner to make.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.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!
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Caretaker check at 4183f61: not a defect. In the scene contract, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right — |
||
| } label: { | ||
| Label("The wall just ends", systemImage: "arrow.right.to.line") | ||
| .frame(maxWidth: .infinity) | ||
| } | ||
| .buttonStyle(.secondaryProminent) | ||
| .accessibilityHint("No corner and nothing in the way. The wall stops here.") | ||
| .accessibilityIdentifier("action.endEnds") | ||
| } | ||
| .transition(.opacity) | ||
| case .overheadQuestion: | ||
|
|
@@ -262,45 +266,42 @@ struct WallWalkScreen: View { | |
| } | ||
|
|
||
| /// The capture gate's coaching (slow down, texture, light, hold steady) comes and goes within | ||
| /// a second while the homeowner walks, and the task under it stays the same, so "Can't get | ||
| /// there" stays put through it: hiding it each time made the button fade in and out under the | ||
| /// a second while the homeowner walks, and the task under it stays the same, so the card's | ||
| /// reply stays put through it: hiding it each time made the button fade in and out under the | ||
| /// homeowner's thumb, and the accessibility audit caught it half faded (CI run 36295565916). | ||
| /// Coaching about tracking itself hides it, since where an end would land needs the phone's | ||
| /// place, as does being past an end. | ||
| /// place, as does being past an end, where the way on is to walk back (#80). No `default`: | ||
| /// a new coaching case has to choose. | ||
| private var coachingHidesReply: Bool { | ||
| switch state.coaching { | ||
| case nil, .slowDown?, .needsTexture?, .tooDark?, .holdSteady?: false | ||
| case .initializing?, .relocalizing?, .trackingLost?, .pastWallEnd?: true | ||
| } | ||
| } | ||
|
|
||
| /// The card's reply, worded for the step by `ScanCopy.reply(for:)` ("Skip this spot" on an | ||
| /// aim step, "Can't get there" on the walk). Its identifier is `action.cannotAccess` on | ||
| /// every step. | ||
| private var reply: InstructionCard.Reply? { | ||
| guard asksForArea, state.marking == nil, state.endQuestion == nil, !state.overheadQuestion, | ||
| !coachingHidesReply, !trayOpen else { return nil } | ||
| if case .seeBehind = state.guidance { | ||
| return InstructionCard.Reply( | ||
| title: ScanCopy.cannotSeeBehind, | ||
| identifier: "action.cannotAccess", | ||
| hint: "Skips the part behind it. An installer will look at it instead.", | ||
| perform: { actions.cannotAccessArea() } | ||
| ) | ||
| } | ||
| if case .walk = state.guidance { | ||
| return InstructionCard.Reply( | ||
| title: "Can't get there", | ||
| identifier: "action.cannotAccess", | ||
| hint: "Ends the wall at the dashed line on the map. An installer will look at what's past it.", | ||
| perform: { actions.cannotAccessArea() } | ||
| ) | ||
| } | ||
| guard state.marking == nil, state.endQuestion == nil, !state.overheadQuestion, !coachingHidesReply, !trayOpen, | ||
| let copy = ScanCopy.reply(for: state.guidance) else { return nil } | ||
| return InstructionCard.Reply( | ||
| title: "Can't get there", | ||
| title: copy.title, | ||
| identifier: "action.cannotAccess", | ||
| hint: "Skips this part of the wall. An installer will look at it instead.", | ||
| perform: { actions.cannotAccessArea() } | ||
| hint: copy.hint, | ||
| perform: { actions.cannotAccessArea() }, | ||
| task: replyTask | ||
| ) | ||
| } | ||
|
|
||
| /// The step the reply answers, in words, for the card's input lock: the step's own words | ||
| /// while coaching shows over it, and the walk without its distance to go, which changes as | ||
| /// the homeowner walks and would lock "Can't get there" again each time. | ||
| private var replyTask: Instruction { | ||
| if case .walk(let side, _) = state.guidance { return ScanCopy.guidance(.walk(side: side, remaining: nil)) } | ||
| return ScanCopy.guidance(state.guidance) | ||
| } | ||
|
|
||
| private var nextWallSymbol: String { | ||
| if case .markNextWall(.left, _) = state.guidance { return "arrow.turn.up.left" } | ||
| return "arrow.turn.up.right" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: SamGu-NRX/BaseScanning
Length of output: 6022
🏁 Script executed:
Repository: SamGu-NRX/BaseScanning
Length of output: 25351
🏁 Script executed:
Repository: SamGu-NRX/BaseScanning
Length of output: 25193
🏁 Script executed:
Repository: SamGu-NRX/BaseScanning
Length of output: 10862
Let walk skips override synthetic coverage.
The frozen wall-walk starts with
reachedRight == 0.9. The right skip is therefore1.0...4.3. AfterreachedRightadvances to4.3,state(at:left:right:lag:)marks cells through about4.0as.covered. The guards at lines 590–591 leave those cells covered instead of.skipped. The left walk has the same issue.This affects
DemoEngine, which powers the UI demo and UI tests. It does not affect productionScanEnginecoverage. In the demo, the wall tape can show the inaccessible span as covered. Add an assertion for both walk directions.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents