Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .pi/orksorksorks/alanvardy-var-1102-drag-to-move/done.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Done

- **Branch / head SHA**: `alanvardy-var-1102-drag-to-move` @ `2c3f41c`
(`fix: clear stale drag state on cancel and reject foreign drops`)
- **Mechanical checks**: `bash scripts/test.sh` → `gate: ok` both before and
after the review fixes. `make test-unit` 485 → 487 tests passing (2 added).
Covers `make build` (iOS sim, warnings-as-errors), `make test`,
`make build-mac`, `make watch-build`, `scripts/tests/run.sh` (26 passed),
`shellcheck`. No warnings flagged; no blockers from mechanical checks.
- **Rebase**: no conflicts — no rebase was in progress and the branch was
already based on `main`.
- **Review outcome**:
- One bounded `reviewer` pass over the 3-file source diff (the `DELETEME`
placeholder removal and step-artifacts commits are chores). Fresh context.
- **Blocker fixed (#1)**: a cancelled drag never reached `performDrop`, so
`draggingChecklistID`/`draggingFolderID` leaked and could drive a move when
a later drag of the other kind passed over rows (silent persisted-order
corruption). Fix: each `onDrag` clears the other kind's id, edit-mode exit
clears both, and `performDrop` rejects a drop unless a drag of its own kind
is in flight. `ContentView.swift`.
- **Fix applied (#2)**: symmetric unknown-id no-op tests for
`moveChecklist(id:onto:)` (`dragChecklistOntoUnknownIDIsANoOp`,
`dragUnknownChecklistIsANoOp`).
- **Fix applied (#3)**: doc note that `moveChecklist(id:onto:)` is called once
per row entered during a live-reorder drag.
- **Optional (declined, remains manual)**: on-device check that a long scrub
over rows settles without oscillation — already an explicit manual item in
`implement.md`; static review cannot confirm SwiftUI runtime behavior.
- **Deferred**: duplicate `import CheckStitchCore` at `ContentView.swift:1,3`
is pre-existing on `main`, out of this diff's scope.
- **Remaining manual items**: the device/visual checks listed in
`implement.md` (Phase 1 checklist drag within/loose, cross-section no-op,
boundary drag, edit-mode tap behavior; Phase 2 folder drag, collapsed-folder
drag, row↔header no-op, chevron/Move-to-Folder still work). Sync/render
tickets cannot close on static evidence — verify the installed bundle on the
target.
27 changes: 27 additions & 0 deletions .pi/orksorksorks/alanvardy-var-1102-drag-to-move/implement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Implementation Summary

## Commits
| Phase | Commit | Description |
|-------|--------|-------------|
| 1 | 534ce2b | Checklist drag-reorder (walking skeleton) |
| 2 | 65cdbc1 | Folder drag-reorder |

## Automated Checks
- [x] `make test-unit` (Phase 1 + Phase 2) — 480 then 485 tests, all passing
- [x] `make build` (iOS simulator, warnings-as-errors) — passed both phases
- [x] `make build-mac` (macOS slice) — passed both phases
- [x] `bash scripts/test.sh` printed `gate: ok` (Phase 2; covers make build/test/build-mac/watch-build, scripts/tests/run.sh, shellcheck)

## Manual Verification Items (from the plan)

Phase 1 — Checklist drag-reorder:
- [ ] `make run`; tap Edit; long-press a checklist row and drag it over another row in the same folder — the dragged row takes that slot and the order survives relaunch.
- [ ] In edit mode, drag a loose checklist over a folder member (and vice versa) — both sections are unchanged (cross-section no-op).
- [ ] In edit mode, drag the first loose row past the last loose row — it lands last (boundary).
- [ ] Leave edit mode: tapping a row still pushes the detail screen, and the remove/folder/chevron controls are gone.

Phase 2 — Folder drag-reorder:
- [ ] `make run`; tap Edit; drag a folder header over another folder header — the folder takes that slot and the order survives relaunch.
- [ ] Drag a collapsed folder's header — it reorders without expanding.
- [ ] Drag a checklist row over a folder header (and a folder header over a checklist row) — no reorder occurs in either direction.
- [ ] The chevron up/down nudges and the "Move to Folder" menu still work.
60 changes: 60 additions & 0 deletions .pi/orksorksorks/alanvardy-var-1102-drag-to-move/medium.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Task

Add a drag-to-move interface to the main checklist list (the `ContentView.swift`
`checklistList` screen, shared by iOS and macOS) so the user can reorder
checklists and folders by dragging instead of (or alongside) the current
up/down nudge buttons.

Two capabilities are requested:
1. **Reorder folders** — drag a folder header to change its position in the list.
2. **Reorder checklists** — drag a checklist row to reorder it within its own
folder (and within the loose group). Moving a checklist *between* folders or
into/out of the loose group is **optional / "nice to have"** — handle it only
if it drops out cleanly from the same drag plumbing; otherwise keep the
existing "move to folder" context-menu action.

The list is **not** a SwiftUI `List` — it is a custom `LazyVStack` inside a
`ScrollView` (see `ContentView.swift:checklistList`), so drag-and-drop must be
built with `.onDrag`/`.onDrop` (+ a `DropDelegate`), not `.onMove`. Reordering a
row inside a folder must map the folder's *filtered* member index onto an index
in the store's *global* `checklists` array, since member order within a folder
is derived from global array order.

Persistence and ordering already exist and must be reused, not rebuilt:
- Folder order **is** the persisted array order; `store.moveFolders(from:to:)`
reorders local-first and stamps no revision. `store.moveChecklists(from:to:)`
is the same for checklists.
- Checklist folder membership is `Checklist.folderID`; `store.moveChecklist(id:toFolder:)`
already files/un-files a checklist (bumps coarse revision for LWW).
- `listVM.moveFolder(id:up:)` / `listVM.moveChecklist(id:up:)` are the existing
up/down nudges this replaces/supplements.

Do not change the data model, codec version, or sync contract — no migration.

## Why MEDIUM

MULTI_MODULE + BROAD_TEST_SURFACE with M1/M2 holding. The change spans the
ContentView list UI, new reorder/position methods in `ChecklistStore` and
`ChecklistListViewModel`, and tests — but the ordering approach (persisted array
order, `folderID`, existing `move*` methods) and the SwiftUI drag/drop technique
are already known, so no research or design sign-off is needed, and there is no
schema/migration or new integration.

## Key files

- `CheckStitch/ContentView.swift` — `checklistList`, `folderSection(for:)`,
`checklistRow(for:)`, the folder/checklist context menus and current up/down
buttons (the drag interface replaces/supplements these).
- `CheckStitch/ChecklistListViewModel.swift` — `moveChecklist(id:toFolder:)`,
`moveFolder(id:up:)`, `moveChecklist(id:up:)`, `checklists(in:)`; add
drag-target methods that map filtered/section indices to global store indices.
- `CheckStitch/ChecklistStore.swift` — `moveChecklists(from:to:)` (≈L457),
`moveChecklists`/`moveChecklist(id:toFolder:)` (≈L483), `moveFolders(from:to:)`
(≈L531). May need a method that reorders within a folder's members, or moves a
checklist into a folder at a position.
- `CheckStitchCore/Sources/CheckStitchCore/Checklist.swift` —
`ChecklistGrouping.sections` / `isLoose` (read-only ordering helpers) —
likely untouched.
- Tests: `CheckStitchTests/ChecklistStoreTests.swift`,
`CheckStitchTests/ChecklistListViewModelTests.swift` (new reorder/position
logic, happy + boundary paths); UI smoke in `CheckStitchUITests/`.
Loading