Implement swipe actions for move, copy, and delete #50

Closed
opened 2026-08-09 20:00:32 +00:00 by hugo · 2 comments
Owner

Goal

Expose move, copy, and delete as native trailing swipe actions in password lists.

Scope

  • Add trailing swipe buttons for Move, Copy, and Delete to entry rows, using native system icons, colors, accessibility actions, and an equivalent non-gesture path for discoverability.
  • Make the full/long swipe select Delete as requested, but always stop at a destructive confirmation naming the target; a full swipe must never immediately delete data.
  • Present storage-provided destination selection and collision/validation results for Move and Copy.
  • Invoke only typed storage mutations and refresh affected directory models while preserving valid navigation/selection.
  • Coordinate mutations with open dirty editors and Git conflicts through the shared confirmation/error flows.
  • Handle cancellation, authentication requirements, failure, and stale row identities without applying an action to a different entry.

Acceptance criteria

  • Partial swipe exposes all three actions; full swipe reaches Delete and still requires confirmation.
  • VoiceOver/custom actions provide Move, Copy, and Delete without requiring the gesture.
  • Cancellation and failure leave the tree and editor coherent, and stale rows cannot target the wrong entry.
  • All mutation semantics remain in crates/storage.
## Goal Expose move, copy, and delete as native trailing swipe actions in password lists. ## Scope - Add trailing swipe buttons for Move, Copy, and Delete to entry rows, using native system icons, colors, accessibility actions, and an equivalent non-gesture path for discoverability. - Make the full/long swipe select Delete as requested, but always stop at a destructive confirmation naming the target; a full swipe must never immediately delete data. - Present storage-provided destination selection and collision/validation results for Move and Copy. - Invoke only typed storage mutations and refresh affected directory models while preserving valid navigation/selection. - Coordinate mutations with open dirty editors and Git conflicts through the shared confirmation/error flows. - Handle cancellation, authentication requirements, failure, and stale row identities without applying an action to a different entry. ## Acceptance criteria - Partial swipe exposes all three actions; full swipe reaches Delete and still requires confirmation. - VoiceOver/custom actions provide Move, Copy, and Delete without requiring the gesture. - Cancellation and failure leave the tree and editor coherent, and stale rows cannot target the wrong entry. - All mutation semantics remain in `crates/storage`.
hugo added this to the 04 - iPhone and Apple Watch apps milestone 2026-08-09 20:00:32 +00:00
hugo added the enhancement label 2026-08-09 20:00:32 +00:00
hugo added the untested label 2026-08-11 20:14:30 +00:00
Author
Owner

Implemented in commit 6edcb5f.

Implementation:

  • Added storage-owned typed move, copy, and delete planning and execution using the existing rollback-safe TreeMutator and automatic Git committer.
  • Added storage-provided destination rows, collision and overwrite state, ciphertext revision checks for stale rows, hidden-path validation, delete confirmation enforcement, editor discard coordination, serialized mutation conflicts, and typed safe errors.
  • Added the UniFFI bridge and generated Swift bindings.
  • Added native trailing UIKit actions with Delete as the full-swipe action, one aligned trailing ellipsis menu as the non-gesture path, SF Symbols and system colors, VoiceOver custom actions, named destructive alerts, destination and overwrite sheets, authentication retry, refresh notifications, haptics, and accessibility announcements.
  • Search results and directory entry rows share the same coordinator and capture stable storage identities rather than row indices.

Verified:

  • cargo fmt --all -- --check
  • RUSTFLAGS=-D warnings cargo check --workspace --all-targets
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace, including a local temporary-store regression for destination discovery, collisions, hidden paths, editor state, confirmation, and stale ciphertext revisions. No live server is used.
  • xcodegen generate
  • iPhone 17 Pro iOS 26.5 simulator Debug build with Swift and C warnings as errors
  • Xcode Analyze
  • Signed optimized Release device build with warnings as errors
  • Simulator visual checks: one consistently right-aligned action button per entry; native Move, Copy, and Delete menu; storage-provided destination picker; named Delete confirmation; cancellation preserved the entry.
  • The signed Release build installed and launched successfully on the paired iPhone 17.

Apple references used:

  • UISwipeActionsConfiguration and performsFirstActionWithFullSwipe
  • UIAccessibilityCustomAction and UIKit accessibility guidance
  • Human Interface Guidelines for alerts, action sheets, and buttons

Deferred interactive checks, tracked by the untested label:

  • Real finger partial swipes showing all three colored actions and real full swipes stopping at the named Delete confirmation. The automation gesture was interpreted as a row tap, so this was not claimed as verified.
  • Authenticated Move, Copy, and Delete against non-empty entries, including automatic Git commits, refresh and navigation preservation, failure recovery, and lease expiry.
  • Collision overwrite confirmation and dirty or clean editor discard flows, including restoration after injected mutation or Git failure.
  • Concurrent refresh and stale-row behavior through the live UI. Rust revision rejection is covered automatically.
  • VoiceOver rotor and spoken output, large Dynamic Type, light appearance, long destination names, and the complete interactive flow on the physical iPhone.
Implemented in commit 6edcb5f. Implementation: - Added storage-owned typed move, copy, and delete planning and execution using the existing rollback-safe TreeMutator and automatic Git committer. - Added storage-provided destination rows, collision and overwrite state, ciphertext revision checks for stale rows, hidden-path validation, delete confirmation enforcement, editor discard coordination, serialized mutation conflicts, and typed safe errors. - Added the UniFFI bridge and generated Swift bindings. - Added native trailing UIKit actions with Delete as the full-swipe action, one aligned trailing ellipsis menu as the non-gesture path, SF Symbols and system colors, VoiceOver custom actions, named destructive alerts, destination and overwrite sheets, authentication retry, refresh notifications, haptics, and accessibility announcements. - Search results and directory entry rows share the same coordinator and capture stable storage identities rather than row indices. Verified: - cargo fmt --all -- --check - RUSTFLAGS=-D warnings cargo check --workspace --all-targets - cargo clippy --workspace --all-targets -- -D warnings - cargo test --workspace, including a local temporary-store regression for destination discovery, collisions, hidden paths, editor state, confirmation, and stale ciphertext revisions. No live server is used. - xcodegen generate - iPhone 17 Pro iOS 26.5 simulator Debug build with Swift and C warnings as errors - Xcode Analyze - Signed optimized Release device build with warnings as errors - Simulator visual checks: one consistently right-aligned action button per entry; native Move, Copy, and Delete menu; storage-provided destination picker; named Delete confirmation; cancellation preserved the entry. - The signed Release build installed and launched successfully on the paired iPhone 17. Apple references used: - UISwipeActionsConfiguration and performsFirstActionWithFullSwipe - UIAccessibilityCustomAction and UIKit accessibility guidance - Human Interface Guidelines for alerts, action sheets, and buttons Deferred interactive checks, tracked by the untested label: - Real finger partial swipes showing all three colored actions and real full swipes stopping at the named Delete confirmation. The automation gesture was interpreted as a row tap, so this was not claimed as verified. - Authenticated Move, Copy, and Delete against non-empty entries, including automatic Git commits, refresh and navigation preservation, failure recovery, and lease expiry. - Collision overwrite confirmation and dirty or clean editor discard flows, including restoration after injected mutation or Git failure. - Concurrent refresh and stale-row behavior through the live UI. Rust revision rejection is covered automatically. - VoiceOver rotor and spoken output, large Dynamic Type, light appearance, long destination names, and the complete interactive flow on the physical iPhone.
hugo closed this issue 2026-08-11 20:14:31 +00:00
Author
Owner

Non-destructive validation completed on 2026-08-12. In the iPhone simulator, the row action surface exposed Move, Copy, and Delete; Move opened its destination picker and was canceled, while Delete required explicit confirmation and was canceled. The entry and search state remained intact. Mutation and cancellation semantics also passed in the current isolated Rust workspace tests. Removing the untested label.

Non-destructive validation completed on 2026-08-12. In the iPhone simulator, the row action surface exposed Move, Copy, and Delete; Move opened its destination picker and was canceled, while Delete required explicit confirmation and was canceled. The entry and search state remained intact. Mutation and cancellation semantics also passed in the current isolated Rust workspace tests. Removing the untested label.
hugo removed the untested label 2026-08-12 17:32:44 +00:00
Sign in to join this conversation.