mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-14 14:19:57 +02:00
docs: add device history UI branch handoff
This commit is contained in:
@@ -29,12 +29,18 @@ Domain docs (reference, do not paste into PRs):
|
|||||||
|
|
||||||
- [`crates/vnidrop/CORE_FLOW.md`](crates/vnidrop/CORE_FLOW.md)
|
- [`crates/vnidrop/CORE_FLOW.md`](crates/vnidrop/CORE_FLOW.md)
|
||||||
- [`crates/vnidrop/tests/README.md`](crates/vnidrop/tests/README.md)
|
- [`crates/vnidrop/tests/README.md`](crates/vnidrop/tests/README.md)
|
||||||
|
- **Saved Devices platform UI:** read
|
||||||
|
[`DEVICE-HISTORY-UI-HANDOFF.md`](DEVICE-HISTORY-UI-HANDOFF.md) before work on
|
||||||
|
`feat/device-history-kmp` or `feat/device-history-apple`; it defines branch
|
||||||
|
ownership, PR bases, product behavior, and completion gates.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Absolute rules
|
## Absolute rules
|
||||||
|
|
||||||
1. Prefer PRs into `master`. Do not merge to `master` locally unless the user asks.
|
1. Prefer PRs into `master`. The Saved Devices platform branches are the
|
||||||
|
documented exception: their PR base is `feat/device-history`. Do not merge to
|
||||||
|
`master` locally unless the user asks.
|
||||||
2. Do not `git push`, force-push, or open a PR unless the user asks.
|
2. Do not `git push`, force-push, or open a PR unless the user asks.
|
||||||
3. If `commit.gpgsign` is enabled, create **signed** commits only. If signing fails
|
3. If `commit.gpgsign` is enabled, create **signed** commits only. If signing fails
|
||||||
(empty `ssh-add -l`), stop and tell the user to unlock the key. Never switch to
|
(empty `ssh-add -l`), stop and tell the user to unlock the key. Never switch to
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# Design — Saved devices and targeted transfers
|
# Design — Saved devices and targeted transfers
|
||||||
|
|
||||||
Status: **production Rust core capability; product UI graduation is deferred**.
|
Status: **production Rust core capability; platform UI implementation is in progress**.
|
||||||
|
|
||||||
The unreleased contact/held-offer/polling prototype has been removed. The
|
The unreleased contact/held-offer/polling prototype has been removed. The
|
||||||
implementation on this branch is the versioned saved-device, device-relationship,
|
implementation on this branch is the versioned saved-device, device-relationship,
|
||||||
and targeted-transfer core described below. Its wire protocol and public core
|
and targeted-transfer core described below. Its wire protocol and public core
|
||||||
surface are production contracts; KMP and Apple product UI remain deferred.
|
surface are production contracts. Platform UI work is coordinated in
|
||||||
|
[`DEVICE-HISTORY-UI-HANDOFF.md`](DEVICE-HISTORY-UI-HANDOFF.md).
|
||||||
|
|
||||||
The feature lets two VniDrop installations remember one another after a
|
The feature lets two VniDrop installations remember one another after a
|
||||||
successful transfer, with explicit consent on both devices. A saved device can
|
successful transfer, with explicit consent on both devices. A saved device can
|
||||||
@@ -13,8 +14,8 @@ then request a new transfer without another invitation, QR scan, or NFC tap.
|
|||||||
The receiver must still approve every transfer.
|
The receiver must still approve every transfer.
|
||||||
|
|
||||||
The Rust core, protocol, persistence, credential-storage integration, and
|
The Rust core, protocol, persistence, credential-storage integration, and
|
||||||
platform contracts are the first delivery scope. Product UI is intentionally
|
platform contracts are complete. KMP and Apple product UI ship from separate
|
||||||
deferred to a separate design and implementation session.
|
branches into `feat/device-history` before the feature targets `master`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
118
DEVICE-HISTORY-UI-HANDOFF.md
Normal file
118
DEVICE-HISTORY-UI-HANDOFF.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# Saved Devices UI handoff
|
||||||
|
|
||||||
|
This document coordinates the platform UI work built on the production Saved
|
||||||
|
Devices and Targeted Transfer core.
|
||||||
|
|
||||||
|
## Branch topology
|
||||||
|
|
||||||
|
| Branch | Ownership | Pull-request base |
|
||||||
|
|---|---|---|
|
||||||
|
| `feat/device-history` | Shared core contract and integration base | `master` only when the complete feature is ready |
|
||||||
|
| `feat/device-history-kmp` | Android, Windows, and Linux Compose UI | `feat/device-history` |
|
||||||
|
| `feat/device-history-apple` | Native iOS and macOS SwiftUI | `feat/device-history` |
|
||||||
|
|
||||||
|
Create both platform branches from the same `feat/device-history` commit. Keep
|
||||||
|
platform work on its matching branch. Open every platform PR against
|
||||||
|
`feat/device-history`, never `master` or the sibling platform branch. When the
|
||||||
|
base advances, merge or rebase `feat/device-history` into the platform branch;
|
||||||
|
do not merge one platform branch into the other.
|
||||||
|
|
||||||
|
## Product contract
|
||||||
|
|
||||||
|
- Saved Device is a top-level product feature, not an experimental setting.
|
||||||
|
- A populated Saved Devices screen has a title-only header. Explanatory copy
|
||||||
|
belongs in the first-use empty state or next to the control that needs it.
|
||||||
|
- The main screen lists saved devices and outstanding consent requests. It does
|
||||||
|
not expose the global Targeted Transfer history.
|
||||||
|
- Selecting a saved device opens a platform-native details surface: bottom
|
||||||
|
sheet on compact mobile layouts and a native inspector, sheet, or dialog on
|
||||||
|
wider layouts. That surface owns Send, label/forget/block actions, and the
|
||||||
|
device's Targeted Transfers with related lifecycle activity, status,
|
||||||
|
progress, and available actions.
|
||||||
|
- Display `localLabel` when present, otherwise the authenticated
|
||||||
|
`remoteDisplayName`. Keep the endpoint ID secondary and diagnostic.
|
||||||
|
- Use each platform's native device iconography and interaction conventions.
|
||||||
|
Equivalent behavior may use separate Apple and Compose implementations.
|
||||||
|
- Label changes are transactional from the UI's perspective: preserve the
|
||||||
|
draft and editor on failure, prevent conflicting dismissal/edit actions while
|
||||||
|
saving, and close only after success.
|
||||||
|
- Invitation Transfer and Targeted Transfer source composition have file,
|
||||||
|
folder, editable-name, replacement, and cleanup parity. Keep the domains
|
||||||
|
distinct after creation.
|
||||||
|
- Every Targeted Transfer still needs receiver approval. Saving a device never
|
||||||
|
grants automatic receipt.
|
||||||
|
- UI and platform code manage pickers and destinations; Rust streams payload
|
||||||
|
bytes. Android folder selection expands SAF trees into file descriptors and
|
||||||
|
relative names, never a directory descriptor.
|
||||||
|
|
||||||
|
Use the exact domain terms in [`CONTEXT.md`](CONTEXT.md) and the security and
|
||||||
|
lifecycle invariants in [`crates/vnidrop/CORE_FLOW.md`](crates/vnidrop/CORE_FLOW.md).
|
||||||
|
The KMP implementation under
|
||||||
|
`shared/src/commonMain/kotlin/com/vnidrop/app/feature/saveddevices/` is a tested
|
||||||
|
behavioral reference, not an Apple visual specification.
|
||||||
|
|
||||||
|
## KMP implementation branch
|
||||||
|
|
||||||
|
Start on `feat/device-history-kmp` and follow
|
||||||
|
[`shared/AGENTS.md`](shared/AGENTS.md) plus
|
||||||
|
[`.codex/skills/compose-skill/SKILL.md`](.codex/skills/compose-skill/SKILL.md).
|
||||||
|
|
||||||
|
The branch owns:
|
||||||
|
|
||||||
|
- `shared/`, `androidApp/`, and `desktopApp/` Saved Devices presentation work;
|
||||||
|
- Material Android and native-feeling Windows/Linux presentations;
|
||||||
|
- per-device details, transfer composition, offers, pairing consent, label
|
||||||
|
editing, and lifecycle actions;
|
||||||
|
- common state-machine tests, JVM Compose interaction tests, and platform
|
||||||
|
adapter tests.
|
||||||
|
|
||||||
|
Before handoff, run `make check-localization`, `make check-shared`, and the
|
||||||
|
relevant Android build. Inspect the actual Android emulator and desktop window;
|
||||||
|
record any host that could not be rendered.
|
||||||
|
|
||||||
|
## Apple implementation branch
|
||||||
|
|
||||||
|
Start on `feat/device-history-apple`. Apple remains native SwiftUI; do not add
|
||||||
|
Apple presentation to `shared/`.
|
||||||
|
|
||||||
|
The branch owns:
|
||||||
|
|
||||||
|
- a top-level Saved Devices destination in the iOS tab bar and macOS sidebar;
|
||||||
|
- an Apple-native Saved Devices model/coordinator and SwiftUI screen;
|
||||||
|
- pairing consent and Targeted Offer presentation outside Experimental
|
||||||
|
Settings;
|
||||||
|
- per-device details and Targeted Transfer lifecycle actions;
|
||||||
|
- iOS/macOS picker and receive-destination integration using the existing
|
||||||
|
platform services;
|
||||||
|
- Swift model tests, UI contract tests, and simulator-rendered visual checks.
|
||||||
|
|
||||||
|
Use the generated production UniFFI surface in
|
||||||
|
`apple/VnidropCore/Sources/VnidropCore/Vnidrop.swift`, including
|
||||||
|
`listSavedDevices`, `listDeviceRelationships`, `listPairingEligibilities`,
|
||||||
|
`listPendingTargetedOffers`, `createTargetedTransfer`,
|
||||||
|
`respondToTargetedOffer`, `listTargetedTransfers`, receive/resume/cancel/delete,
|
||||||
|
label, forget, and block operations. Wrap those calls through the existing
|
||||||
|
Apple `CoreGateway` / `CoreRepository` boundary rather than invoking generated
|
||||||
|
bindings from SwiftUI views.
|
||||||
|
|
||||||
|
Use SF Symbols and native iOS/macOS controls even when that duplicates Compose
|
||||||
|
presentation code. Share behavior and vocabulary across platforms, not widget
|
||||||
|
implementations. Before handoff, run `make check-localization` and
|
||||||
|
`make check-apple`, then inspect the affected iOS and macOS states in real
|
||||||
|
simulator/app hosts.
|
||||||
|
|
||||||
|
## Completion gate
|
||||||
|
|
||||||
|
Each platform PR is ready only when it demonstrates:
|
||||||
|
|
||||||
|
1. mutual consent creates and names a Saved Device correctly;
|
||||||
|
2. an already-saved pair is not prompted to save again;
|
||||||
|
3. files and folders can be composed, changed, and sent to one saved device;
|
||||||
|
4. Targeted Transfers are absent from the main device list and visible in the
|
||||||
|
selected device's details surface;
|
||||||
|
5. receive, resume, cancel, delete, progress, and terminal states survive
|
||||||
|
refresh/restart as defined by the core snapshot;
|
||||||
|
6. label failure preserves the draft and retry path;
|
||||||
|
7. empty, populated, busy, error, long-name, and destructive-confirmation
|
||||||
|
states are rendered and visually inspected;
|
||||||
|
8. ordinary Invitation Transfer flows remain unchanged.
|
||||||
Reference in New Issue
Block a user