diff --git a/.agents/skills/verify-deepseekbot/features/phone-pairing.md b/.agents/skills/verify-deepseekbot/features/phone-pairing.md index 2c0d7addb7..aba2669b88 100644 --- a/.agents/skills/verify-deepseekbot/features/phone-pairing.md +++ b/.agents/skills/verify-deepseekbot/features/phone-pairing.md @@ -15,7 +15,7 @@ A Human pairs the phone app with their Host by a one-time QR code, and the phone ## How to get to it (user POV) - Computer: Bot mode → settings → Devices → Pair a phone. The dialog shows the QR code and a copy link; the Devices list has Revoke. -- Phone: the app opens on "Pair with your computer"; scan the code or paste the link, then tap Pair. +- Phone: first use opens "Pair with your computer". From an existing session: Workspaces → Computers → Pair a new computer. Scan the code or paste the link, then tap Pair. Cloud → Join by link or QR is the separate cloud invitation path; its preview identifies organization membership versus one-channel guest access. The category tabs are the first drawer row; swipe, backdrop, Android Back and accessibility escape dismiss it. ## Driving it with verify-app diff --git a/.github/pr-screenshots/2171-drawer-headers/README.md b/.github/pr-screenshots/2171-drawer-headers/README.md new file mode 100644 index 0000000000..b5861688ff --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/README.md @@ -0,0 +1,26 @@ +# Drawer headers — Batch 23 + +Runtime `4185d28a380bd37f68eafb765d28d24ee947af4a`; base `3be6b52c384812f801d2b9d58013580c0d6e4c0f`; installed native `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`. [Runtime CI](https://github.com/BotHarness/DeepSeekBot/actions/runs/39109396184) passed all applicable jobs. + +The assigned existing iOS 26 Simulator rendered both views at 402 × 874 in English. Before/after pairs use matching default text, light theme and signed-out data. No new dependency, native build, account login, service mutation or Prod change. + +## Results + +- Workspace drawer and generic statistics Sheet: default/intermediate/maximum Dynamic Type × light/dark captured and inspected. Long titles wrap; maximum-size close actually clicked in both surfaces. Sheet body was scrolled; the secondary Got it button was partly clipped in the captured position, so this is not a full body-action reachability qualification. +- Normal-size iOS title uses native glass from existing Expo UI. Larger text uses an opaque rounded rectangle. Close is a separate 44pt target. Android source/bundle passed but was not driven natively. +- Workspace close/reopen and backdrop dismissal were actually performed. The 3.7-second recording and 14-cell contact sheet were inspected. +- Real Settings Reduce Transparency toggle was observed checked, App returned to opaque title/close, then the original unchecked state and glass rendering were restored. No app restart was needed for the setting change. +- Original statistics preferences were backed up privately, noticeSeen was temporarily cleared to show the production Sheet, then the original bytes were restored. Development telemetry transport was unconfigured. No telemetry identity or private file is published. + +## First failures retained + +- Initial sandbox source run could not bind loopback; permitted rerun passed 649 tests / 8 skipped. +- Initial CI rejected comments/useEffect; external-store subscription replaced it. The final source-policy, typecheck, build, affected tests and both mobile bundles passed. +- First native maximum-light glass title became a dark ellipse around multiline text (`first-pass/`). Final runtime uses the rounded opaque large-text treatment; all six cases rerun. +- Initial capture was during bundling and was discarded from final comparisons. First system-switch label click did not toggle the switch; unchecked state and unchanged glass were retained. Actual switch tap then produced checked → opaque → unchecked → glass evidence. + +## Boundaries and cleanup + +Settings/SheetStack remain unchanged; this does not requalify #2112 or claim every drawer migrated. Android, physical phone, VoiceOver/Human and older-iOS rendering remain unverified. Source and iOS results do not close those gates. + +Large/light and Reduce Transparency off restored; original statistics preference file restored byte-for-byte; own App, driver and Metro stopped. Installed app/data/Keychain, signed Products, rollback, three original QA documents, physical-phone lane and all Hosts preserved. No merge. diff --git a/.github/pr-screenshots/2171-drawer-headers/after-drawer.png b/.github/pr-screenshots/2171-drawer-headers/after-drawer.png new file mode 100644 index 0000000000..b7bd60c61d Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/after-drawer.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/after-sheet.png b/.github/pr-screenshots/2171-drawer-headers/after-sheet.png new file mode 100644 index 0000000000..93da6fc6a5 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/after-sheet.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/before-drawer.png b/.github/pr-screenshots/2171-drawer-headers/before-drawer.png new file mode 100644 index 0000000000..ed68d15f6d Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/before-drawer.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/before-sheet.png b/.github/pr-screenshots/2171-drawer-headers/before-sheet.png new file mode 100644 index 0000000000..d4f45f88ba Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/before-sheet.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-accessibility-extra-extra-extra-large-dark.png b/.github/pr-screenshots/2171-drawer-headers/drawer-accessibility-extra-extra-extra-large-dark.png new file mode 100644 index 0000000000..ef9d04456b Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-accessibility-extra-extra-extra-large-dark.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-accessibility-extra-extra-extra-large-light.png b/.github/pr-screenshots/2171-drawer-headers/drawer-accessibility-extra-extra-extra-large-light.png new file mode 100644 index 0000000000..bd6ede9c1c Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-accessibility-extra-extra-extra-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-close-reopen.mp4 b/.github/pr-screenshots/2171-drawer-headers/drawer-close-reopen.mp4 new file mode 100644 index 0000000000..aa1f34e6fe Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-close-reopen.mp4 differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-extra-extra-extra-large-dark.png b/.github/pr-screenshots/2171-drawer-headers/drawer-extra-extra-extra-large-dark.png new file mode 100644 index 0000000000..6f67af1005 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-extra-extra-extra-large-dark.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-extra-extra-extra-large-light.png b/.github/pr-screenshots/2171-drawer-headers/drawer-extra-extra-extra-large-light.png new file mode 100644 index 0000000000..75afe8a46c Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-extra-extra-extra-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-large-dark.png b/.github/pr-screenshots/2171-drawer-headers/drawer-large-dark.png new file mode 100644 index 0000000000..92da6093d0 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-large-dark.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-large-light.png b/.github/pr-screenshots/2171-drawer-headers/drawer-large-light.png new file mode 100644 index 0000000000..a638b0df75 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/drawer-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/drawer-matrix.json b/.github/pr-screenshots/2171-drawer-headers/drawer-matrix.json new file mode 100644 index 0000000000..15a4beea44 --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/drawer-matrix.json @@ -0,0 +1,38 @@ +[ + { + "kind": "drawer", + "size": "large", + "theme": "light", + "closeAccessible": true + }, + { + "kind": "drawer", + "size": "large", + "theme": "dark", + "closeAccessible": true + }, + { + "kind": "drawer", + "size": "extra-extra-extra-large", + "theme": "light", + "closeAccessible": true + }, + { + "kind": "drawer", + "size": "extra-extra-extra-large", + "theme": "dark", + "closeAccessible": true + }, + { + "kind": "drawer", + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "closeAccessible": true + }, + { + "kind": "drawer", + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "closeAccessible": true + } +] diff --git a/.github/pr-screenshots/2171-drawer-headers/first-pass/sheet-accessibility-extra-extra-extra-large-light.png b/.github/pr-screenshots/2171-drawer-headers/first-pass/sheet-accessibility-extra-extra-extra-large-light.png new file mode 100644 index 0000000000..1c271e33bc Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/first-pass/sheet-accessibility-extra-extra-extra-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/first-pass/transparency-not-enabled.png b/.github/pr-screenshots/2171-drawer-headers/first-pass/transparency-not-enabled.png new file mode 100644 index 0000000000..72b9a7a6a4 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/first-pass/transparency-not-enabled.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/proof.json b/.github/pr-screenshots/2171-drawer-headers/proof.json new file mode 100644 index 0000000000..ba0f4153e2 --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/proof.json @@ -0,0 +1,36 @@ +{ + "issue": 2171, + "pr": 2172, + "base": "3be6b52c384812f801d2b9d58013580c0d6e4c0f", + "runtime": "4185d28a380bd37f68eafb765d28d24ee947af4a", + "native": "494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b", + "ci": 39109396184, + "environment": "local iOS Simulator, existing UAT signed-out configuration", + "viewport": "402x874", + "matrices": { + "drawer": "3 text sizes x light/dark", + "sheet": "3 text sizes x light/dark" + }, + "pass": [ + "native title material", + "maximum-text close in drawer and sheet", + "drawer close/reopen/backdrop", + "sheet body scroll", + "Reduce Transparency on/opaque and off/glass restored" + ], + "unverified": [ + "Android native", + "physical phone", + "Human and VoiceOver", + "older iOS native fallback", + "Settings / SheetStack adoption" + ], + "cleanup": [ + "large/light restored", + "Reduce Transparency restored off", + "original statistics preferences restored byte-for-byte", + "own app/driver/Metro stopped", + "no login or service writes", + "other Hosts and physical phone unchanged" + ] +} diff --git a/.github/pr-screenshots/2171-drawer-headers/recording-contact.png b/.github/pr-screenshots/2171-drawer-headers/recording-contact.png new file mode 100644 index 0000000000..7a4cbc9f56 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/recording-contact.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/reduce-transparency.png b/.github/pr-screenshots/2171-drawer-headers/reduce-transparency.png new file mode 100644 index 0000000000..61f4b8facb Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/reduce-transparency.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/restored-glass.png b/.github/pr-screenshots/2171-drawer-headers/restored-glass.png new file mode 100644 index 0000000000..9c0e852fa2 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/restored-glass.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-accessibility-extra-extra-extra-large-dark.png b/.github/pr-screenshots/2171-drawer-headers/sheet-accessibility-extra-extra-extra-large-dark.png new file mode 100644 index 0000000000..f71e413f01 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-accessibility-extra-extra-extra-large-dark.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-accessibility-extra-extra-extra-large-light.png b/.github/pr-screenshots/2171-drawer-headers/sheet-accessibility-extra-extra-extra-large-light.png new file mode 100644 index 0000000000..90add8f205 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-accessibility-extra-extra-extra-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-extra-extra-extra-large-dark.png b/.github/pr-screenshots/2171-drawer-headers/sheet-extra-extra-extra-large-dark.png new file mode 100644 index 0000000000..ef729088d0 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-extra-extra-extra-large-dark.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-extra-extra-extra-large-light.png b/.github/pr-screenshots/2171-drawer-headers/sheet-extra-extra-extra-large-light.png new file mode 100644 index 0000000000..9dcb892770 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-extra-extra-extra-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-large-dark.png b/.github/pr-screenshots/2171-drawer-headers/sheet-large-dark.png new file mode 100644 index 0000000000..1cd03b44e0 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-large-dark.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-large-light.png b/.github/pr-screenshots/2171-drawer-headers/sheet-large-light.png new file mode 100644 index 0000000000..93da6fc6a5 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-large-light.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-matrix.json b/.github/pr-screenshots/2171-drawer-headers/sheet-matrix.json new file mode 100644 index 0000000000..fa8640f830 --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/sheet-matrix.json @@ -0,0 +1,38 @@ +[ + { + "kind": "sheet", + "size": "large", + "theme": "light", + "closeAccessible": true + }, + { + "kind": "sheet", + "size": "large", + "theme": "dark", + "closeAccessible": true + }, + { + "kind": "sheet", + "size": "extra-extra-extra-large", + "theme": "light", + "closeAccessible": true + }, + { + "kind": "sheet", + "size": "extra-extra-extra-large", + "theme": "dark", + "closeAccessible": true + }, + { + "kind": "sheet", + "size": "accessibility-extra-extra-extra-large", + "theme": "light", + "closeAccessible": true + }, + { + "kind": "sheet", + "size": "accessibility-extra-extra-extra-large", + "theme": "dark", + "closeAccessible": true + } +] diff --git a/.github/pr-screenshots/2171-drawer-headers/sheet-max-bottom.png b/.github/pr-screenshots/2171-drawer-headers/sheet-max-bottom.png new file mode 100644 index 0000000000..cd71901e56 Binary files /dev/null and b/.github/pr-screenshots/2171-drawer-headers/sheet-max-bottom.png differ diff --git a/.github/pr-screenshots/2171-drawer-headers/transparency-app.txt b/.github/pr-screenshots/2171-drawer-headers/transparency-app.txt new file mode 100644 index 0000000000..aee3b78b40 --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/transparency-app.txt @@ -0,0 +1,33 @@ +Page: ai.botharness.deepseekbot.dev +App: ai.botharness.deepseekbot.dev +Snapshot: 27 visible nodes +Simulator AX snapshot inapplicable (system-surface-host-lingering); used XCTest, which read app content: the system surface host process was still running but no longer presenting. +@e1 [application] "DeepSeekBot Dev" +@e2 [other] "gearshape.fill" +@e3 [image] "gearshape.fill" +@e4 [navigation-bar] "Back" +@e5 [button] "Back" +@e6 [text] "Cloud services" +@e7 [button] "Workspaces" +@e8 [other] "tob-instance-uat" +@e9 [scroll-area] "Import the UAT configuration supplied by your deployer. Cloud sign-in is separate from pairing a computer." [scrollable] + [content below scroll-area hidden] +@e10 [other] [same label as parent] +@e11 [button] "Scan configuration" +@e12 [button] "Paste configuration" +@e13 [text] "https://tob-service-uat.yangmufeng233.workers.dev" +@e14 [text] "UAT" +@e15 [text] "Signed out" +@e16 [button] "Sign in" +@e17 [other] "Workspaces" +@e18 [button] "Close workspaces" +@e19 [scroll-area] "Computers" [scrollable] + [content below scroll-area hidden] +@e20 [other] "Computers" +@e21 [text] "Cloud workspaces" +@e22 [button] "tob-service-uat.yangmufeng233.workers.dev · Sign in to continue" +@e23 [button] "Join with invitation" +@e24 [button] "Create workspace" +@e25 [button] "Pair a new computer" +@e26 [button] "Cloud services" +@e27 [button] "Notifications" diff --git a/.github/pr-screenshots/2171-drawer-headers/transparency-enabled.txt b/.github/pr-screenshots/2171-drawer-headers/transparency-enabled.txt new file mode 100644 index 0000000000..9c0988d5fc --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/transparency-enabled.txt @@ -0,0 +1,23 @@ +Page: com.apple.Preferences +App: com.apple.Preferences +Snapshot: 18 visible nodes +Simulator AX snapshot inapplicable (system-surface-host-lingering); used XCTest, which read app content: the system surface host process was still running but no longer presenting. +@e1 [application] "Settings" +@e2 [navigation-bar] "Back" +@e3 [button] "Back" +@e4 [text] "Display & Text Size" +@e5 [table] "Bold Text" + [content below table hidden] +@e6 [switch] "Bold Text" [unchecked] +@e7 [cell] "Larger Text, On" +@e8 [switch] "Button Shapes" [unchecked] +@e9 [switch] "On/Off Labels" [unchecked] +@e10 [link] "What's new in Display & Text Size…" +@e11 [switch] "Reduce Transparency" [checked] +@e12 [other] "Improve contrast by reducing transparency and blurs on some backgrounds to increase legibility." +@e13 [switch] "Increase Contrast" [unchecked] +@e14 [other] "Increase color contrast between app foreground and background colors." +@e15 [switch] "Differentiate Without Color" [unchecked] +@e16 [other] "Replaces user interface items that rely solely on color to convey information with alternatives." +@e17 [switch] "Prefer Horizontal Text" [unchecked] +@e18 [other] "Prefer horizontal text in languages that support vertical text." diff --git a/.github/pr-screenshots/2171-drawer-headers/transparency-restored.txt b/.github/pr-screenshots/2171-drawer-headers/transparency-restored.txt new file mode 100644 index 0000000000..dd68a451cb --- /dev/null +++ b/.github/pr-screenshots/2171-drawer-headers/transparency-restored.txt @@ -0,0 +1,23 @@ +Page: com.apple.Preferences +App: com.apple.Preferences +Snapshot: 18 visible nodes +Simulator AX snapshot inapplicable (system-surface-host-lingering); used XCTest, which read app content: the system surface host process was still running but no longer presenting. +@e1 [application] "Settings" +@e2 [navigation-bar] "Back" +@e3 [button] "Back" +@e4 [text] "Display & Text Size" +@e5 [table] "Bold Text" + [content below table hidden] +@e6 [switch] "Bold Text" [unchecked] +@e7 [cell] "Larger Text, On" +@e8 [switch] "Button Shapes" [unchecked] +@e9 [switch] "On/Off Labels" [unchecked] +@e10 [link] "What's new in Display & Text Size…" +@e11 [switch] "Reduce Transparency" [unchecked] +@e12 [other] "Improve contrast by reducing transparency and blurs on some backgrounds to increase legibility." +@e13 [switch] "Increase Contrast" [unchecked] +@e14 [other] "Increase color contrast between app foreground and background colors." +@e15 [switch] "Differentiate Without Color" [unchecked] +@e16 [other] "Replaces user interface items that rely solely on color to convey information with alternatives." +@e17 [switch] "Prefer Horizontal Text" [unchecked] +@e18 [other] "Prefer horizontal text in languages that support vertical text." diff --git a/.github/pr-screenshots/2174-drawer-compact/README.md b/.github/pr-screenshots/2174-drawer-compact/README.md new file mode 100644 index 0000000000..1e70bb1d0d --- /dev/null +++ b/.github/pr-screenshots/2174-drawer-compact/README.md @@ -0,0 +1,13 @@ +# Compact workspace drawer — native evidence + +Final drawer source `dc15ffd3a7003ef0c0f4110f834f02f15a990e6c`, integrated `1376b50b1f8358d9d9b22c89e55901fb5a141d24`; retained native `494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b`. No native dependency/config changes. Real shared iOS Simulator screenshots, 402 × 874, English. + +`before-*` is the prior title/X + mixed Add iteration at source `59fc97fd7bada6d54cbae1feacc4d93d032e4c82`. The same empty-computer/signed-out-UAT fixture, viewport and themes are used. The exposed screen behind the drawer differs; compare the drawer only. These are not screenshots of the PR base branch. Earlier base evidence remains in `../2174-drawer-tabs/` and is superseded for final appearance. + +`*-default-*`, `*-intermediate-*`, `*-max-*`, `join-direct` and `pair-direct` use the final source. `cloud-max-scrolled-dark` shows the address after a swipe in the constrained middle list; the footer stayed at x0/y757.6667/w342/h78.3333. A duplicate footer under the backdrop was found during review, removed, and these final screenshots recaptured. + +Naming screenshots use source `f2d0f4af3ebeecfe5df9f25d2bc1a3636340531d`, integrated `9e77d9810ad642388ed8ac8bcd9a4b9725f181c0`; naming code is identical in the final source. Native edit changed the display name to `TOB UAT`, saved, survived cold restart, then restored `tob-instance-uat` and cold-read it back. No login, credentials, Host identity or organization name changed. `pair-name*` only verifies the optional input; no pairing was redeemed. Driver keystroke injection opened Expo's development menu, so native clipboard Paste was used for this nonsecret test name. + +Local checks: typecheck, focused lint/format/source-policy/release-ledger checks; 74 affected focused tests plus 14 host-look/pairing-telemetry tests at f2d0 (counts overlap). After the backdrop-only fix: typecheck and 19 drawer/style tests passed. CI status is recorded in the PR, separately from these runtime checks. + +Limits: no Android/physical/VoiceOver/Human acceptance; no signed-in org/guest fixture or actual named-computer pairing in this run. The previously observed Pair-modal → cloud-services root-drawer overlay issue remains unqualified; the normal cold-open path works. This is not a full navigation or authentication pass. No production change or merge. diff --git a/.github/pr-screenshots/2174-drawer-compact/before-cloud-dark.png b/.github/pr-screenshots/2174-drawer-compact/before-cloud-dark.png new file mode 100644 index 0000000000..33dde0ceca Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/before-cloud-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/before-cloud-light.png b/.github/pr-screenshots/2174-drawer-compact/before-cloud-light.png new file mode 100644 index 0000000000..161e941e90 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/before-cloud-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/before-computers-dark.png b/.github/pr-screenshots/2174-drawer-compact/before-computers-dark.png new file mode 100644 index 0000000000..0de82d4d75 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/before-computers-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/before-computers-light.png b/.github/pr-screenshots/2174-drawer-compact/before-computers-light.png new file mode 100644 index 0000000000..17cc4c59c0 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/before-computers-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-default-dark.png b/.github/pr-screenshots/2174-drawer-compact/cloud-default-dark.png new file mode 100644 index 0000000000..2edf3010f5 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-default-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-default-light.png b/.github/pr-screenshots/2174-drawer-compact/cloud-default-light.png new file mode 100644 index 0000000000..88043f6b85 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-default-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-intermediate-dark.png b/.github/pr-screenshots/2174-drawer-compact/cloud-intermediate-dark.png new file mode 100644 index 0000000000..5e864512f5 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-intermediate-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-intermediate-light.png b/.github/pr-screenshots/2174-drawer-compact/cloud-intermediate-light.png new file mode 100644 index 0000000000..99be202dab Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-intermediate-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-max-dark.png b/.github/pr-screenshots/2174-drawer-compact/cloud-max-dark.png new file mode 100644 index 0000000000..e0a2380834 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-max-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-max-light.png b/.github/pr-screenshots/2174-drawer-compact/cloud-max-light.png new file mode 100644 index 0000000000..99bf1d0054 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-max-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/cloud-max-scrolled-dark.png b/.github/pr-screenshots/2174-drawer-compact/cloud-max-scrolled-dark.png new file mode 100644 index 0000000000..9386b032e0 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/cloud-max-scrolled-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/computers-default-dark.png b/.github/pr-screenshots/2174-drawer-compact/computers-default-dark.png new file mode 100644 index 0000000000..70e1cb4c03 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/computers-default-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/computers-default-light.png b/.github/pr-screenshots/2174-drawer-compact/computers-default-light.png new file mode 100644 index 0000000000..db6685942c Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/computers-default-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/computers-intermediate-dark.png b/.github/pr-screenshots/2174-drawer-compact/computers-intermediate-dark.png new file mode 100644 index 0000000000..b710be7d4a Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/computers-intermediate-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/computers-intermediate-light.png b/.github/pr-screenshots/2174-drawer-compact/computers-intermediate-light.png new file mode 100644 index 0000000000..d9e2c4daba Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/computers-intermediate-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/computers-max-dark.png b/.github/pr-screenshots/2174-drawer-compact/computers-max-dark.png new file mode 100644 index 0000000000..1466c4365f Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/computers-max-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/computers-max-light.png b/.github/pr-screenshots/2174-drawer-compact/computers-max-light.png new file mode 100644 index 0000000000..1ff42a6b8f Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/computers-max-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/join-direct.png b/.github/pr-screenshots/2174-drawer-compact/join-direct.png new file mode 100644 index 0000000000..60ce9b328e Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/join-direct.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/name-restored.png b/.github/pr-screenshots/2174-drawer-compact/name-restored.png new file mode 100644 index 0000000000..f4ee1f28f1 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/name-restored.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/pair-direct.png b/.github/pr-screenshots/2174-drawer-compact/pair-direct.png new file mode 100644 index 0000000000..b9f0f1375a Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/pair-direct.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/pair-name-keyboard.png b/.github/pr-screenshots/2174-drawer-compact/pair-name-keyboard.png new file mode 100644 index 0000000000..0826a1b0b7 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/pair-name-keyboard.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/pair-name.png b/.github/pr-screenshots/2174-drawer-compact/pair-name.png new file mode 100644 index 0000000000..b1d0ee5e3a Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/pair-name.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/proof.json b/.github/pr-screenshots/2174-drawer-compact/proof.json new file mode 100644 index 0000000000..524dd85ffe --- /dev/null +++ b/.github/pr-screenshots/2174-drawer-compact/proof.json @@ -0,0 +1,47 @@ +{ + "issue": 2174, + "pr": 2175, + "source": "dc15ffd3a7003ef0c0f4110f834f02f15a990e6c", + "integrated": "1376b50b1f8358d9d9b22c89e55901fb5a141d24", + "native": "494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b", + "beforeSource": "59fc97fd7bada6d54cbae1feacc4d93d032e4c82", + "beforeIntegrated": "9a73f9c21440235d8caa6fdc9f7d65d5dc6dfde0", + "namingSource": "f2d0f4af3ebeecfe5df9f25d2bc1a3636340531d", + "namingIntegrated": "9e77d9810ad642388ed8ac8bcd9a4b9725f181c0", + "viewport": "402x874", + "locale": "en", + "fixture": "empty Computer directory and signed-out public UAT cloud service", + "passed": [ + "Computers/Cloud tab selection and independent contextual Add destinations", + "fixed Notifications footer in both tabs; cloud management only in Cloud", + "default/intermediate/maximum Dynamic Type in light/dark", + "maximum text middle-list swipe exposes the address while Notifications rect remains unchanged", + "left-swipe dismissal", + "local cloud name save and cold-start persistence; exact original name restored and cold-read back", + "computer optional name input; no pairing redeemed" + ], + "footerRectAtMax": { + "x": 0, + "y": 757.6666717529297, + "width": 342, + "height": 78.33331298828125 + }, + "unverified": [ + "Android native and physical phone", + "VoiceOver and Human acceptance", + "signed-in organization/member/guest rendering on this revision", + "real computer pairing with name persistence", + "full keyboard/text-size matrix and every footer destination", + "Reduce Transparency toggle" + ], + "knownCaveat": "Opening cloud-services from the native Pair modal can hide the root drawer; normal cold-open path works. Regression origin is not established; full navigation acceptance is not claimed.", + "correction": "Native review at f2d0 found duplicate footer in backdrop. dc15 removed only that duplicate; all final drawer layout screenshots and contextual Add actions were recaptured. Naming code is unchanged.", + "comparisonLimit": "Before/after use the same viewport, theme, locale and drawer fixture. The exposed underlying route differs (pairing vs invitation), so comparison is limited to the drawer.", + "cleanup": [ + "original UAT display name restored and cold-read back", + "driver closed; own Metro stopped", + "qa/batch-24 and original three untracked documents preserved", + "light/large and original locale restored; task clipboard cleared", + "no account/Host/Prod writes, pairing redemption, native build or merge" + ] +} diff --git a/.github/pr-screenshots/2174-drawer-compact/rename-keyboard.png b/.github/pr-screenshots/2174-drawer-compact/rename-keyboard.png new file mode 100644 index 0000000000..7d3f02b6ab Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/rename-keyboard.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/renamed-after-restart.png b/.github/pr-screenshots/2174-drawer-compact/renamed-after-restart.png new file mode 100644 index 0000000000..1a379ed759 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/renamed-after-restart.png differ diff --git a/.github/pr-screenshots/2174-drawer-compact/renamed-cloud.png b/.github/pr-screenshots/2174-drawer-compact/renamed-cloud.png new file mode 100644 index 0000000000..38b7707bee Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-compact/renamed-cloud.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/README.md b/.github/pr-screenshots/2174-drawer-tabs/README.md new file mode 100644 index 0000000000..f6de575750 --- /dev/null +++ b/.github/pr-screenshots/2174-drawer-tabs/README.md @@ -0,0 +1,7 @@ +# Drawer tabs and Add screenshots + +Real shared iOS Simulator captures for #2175, 402 × 874, English. Before and after use the same retained QA computer and signed-out public UAT configuration; there are no credentials in these images. The service address shown is the public UAT endpoint. + +The before view combines both lists and three direct actions. The after views show Computers and Cloud separately and the new Add chooser. The chooser has no old modal counterpart: the old direct actions are its before state. `proof.json` binds source, integrated batch and native identities. + +Navigation checks reached the invitation and pairing pages without signing in, accepting an invitation or changing pairing. Maximum-text images show wrapping and a scrollable chooser; they do not establish a complete accessibility matrix. A nested native-modal route observation remains open in the proof; Android, physical phone and Human QA are unverified. The shared environment was restored after capture. diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-add-dark.png b/.github/pr-screenshots/2174-drawer-tabs/after-add-dark.png new file mode 100644 index 0000000000..8b5b87487c Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-add-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-add-light.png b/.github/pr-screenshots/2174-drawer-tabs/after-add-light.png new file mode 100644 index 0000000000..12f421ccec Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-add-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-add-max-light.png b/.github/pr-screenshots/2174-drawer-tabs/after-add-max-light.png new file mode 100644 index 0000000000..c5a14d767c Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-add-max-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-add-max-scrolled.png b/.github/pr-screenshots/2174-drawer-tabs/after-add-max-scrolled.png new file mode 100644 index 0000000000..204c4f2275 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-add-max-scrolled.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-cloud-dark.png b/.github/pr-screenshots/2174-drawer-tabs/after-cloud-dark.png new file mode 100644 index 0000000000..031e59ea52 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-cloud-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-cloud-light.png b/.github/pr-screenshots/2174-drawer-tabs/after-cloud-light.png new file mode 100644 index 0000000000..b1d25609a8 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-cloud-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-cloud-max-light.png b/.github/pr-screenshots/2174-drawer-tabs/after-cloud-max-light.png new file mode 100644 index 0000000000..f2483bfdf3 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-cloud-max-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-computers-dark.png b/.github/pr-screenshots/2174-drawer-tabs/after-computers-dark.png new file mode 100644 index 0000000000..af12aee7ca Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-computers-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/after-computers-light.png b/.github/pr-screenshots/2174-drawer-tabs/after-computers-light.png new file mode 100644 index 0000000000..7b4f7eb98c Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/after-computers-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/before-dark.png b/.github/pr-screenshots/2174-drawer-tabs/before-dark.png new file mode 100644 index 0000000000..ea6ec03fbd Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/before-dark.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/before-light.png b/.github/pr-screenshots/2174-drawer-tabs/before-light.png new file mode 100644 index 0000000000..3fd9da8713 Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/before-light.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/join-destination.png b/.github/pr-screenshots/2174-drawer-tabs/join-destination.png new file mode 100644 index 0000000000..8e15401aec Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/join-destination.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/pair-destination.png b/.github/pr-screenshots/2174-drawer-tabs/pair-destination.png new file mode 100644 index 0000000000..f22f38e69e Binary files /dev/null and b/.github/pr-screenshots/2174-drawer-tabs/pair-destination.png differ diff --git a/.github/pr-screenshots/2174-drawer-tabs/proof.json b/.github/pr-screenshots/2174-drawer-tabs/proof.json new file mode 100644 index 0000000000..3348450684 --- /dev/null +++ b/.github/pr-screenshots/2174-drawer-tabs/proof.json @@ -0,0 +1,39 @@ +{ + "issue": 2174, + "pr": 2175, + "source": "6292fbf41123bc583f813116e349ac2788e3871a", + "baseSource": "e8472aab4a0e22c0404f99a44d6831dcfe5d0988", + "baseBatch": "bfbcc648fa789ed551c2249b1a392f9341128f04", + "afterBatch": "06c92fc78b71643f6cdd74d42d50913ea92d640a", + "main": "648c1202c44f5a5e82ce22596682934745705cef", + "native": "494a20f1eb4f0666a2c90bc3c758af4e7ff5f46b", + "viewport": "402x874", + "locale": "English", + "environment": "shared iOS 26 Simulator, retained QA computer and signed-out public UAT configuration", + "passed": [ + "Computers/Cloud selected tabs and separate directories", + "one Add target with decorative icons", + "Add close returns to selected tab", + "Add opens existing invitation page", + "Add opens existing pairing page", + "normal text light/dark actual screenshots", + "maximum text wraps; Add opens, chooser scrolls, close works" + ], + "unverified": [ + "Android native", + "physical phone", + "Human/VoiceOver", + "new login or invitation acceptance", + "full large-text matrix and all footer actions", + "Reduce Transparency toggle in this run" + ], + "observation": "After opening Pair (native modal) and following a cloud-services deep link, Workspaces did not visibly overlay the native modal. A cold reopen to the normal cloud-services route restored the working drawer. This route is not marked passed; regression origin not established.", + "cleanup": [ + "driver closed", + "own Metro stopped; 8091 free", + "qa/batch-24 restored at main648c1202c", + "light/large restored", + "three original untracked QA documents retained", + "no account, pairing or Host writes; no Prod or merge" + ] +} diff --git a/apps/mobile/DESIGN.md b/apps/mobile/DESIGN.md index 9051cf334b..dee4eda512 100644 --- a/apps/mobile/DESIGN.md +++ b/apps/mobile/DESIGN.md @@ -24,7 +24,7 @@ References: [Apple toolbars](https://developer.apple.com/design/human-interface- The shell is set by [ADR-0211](../../docs/adr/0211-the-mobile-app-has-two-tabs-with-settings-and-hosts-in-the-header.md): what the Human does most sits under the thumb, and what they do rarely sits in the header. -- **One workspace drawer, two connection types.** Computers are paired Hosts; cloud workspaces belong to an explicitly trusted TOB instance. The existing left drawer is shared across both, with Computers and Cloud workspaces sections. Cloud headers expose the same workspace switcher. A guest sees the organization initial/name and “invited channels only”; selecting it shows only current channel grants. Instance domains disambiguate identically named workspaces. The list and its join/create/pair actions scroll together at large text sizes. +- **One workspace drawer, two connection types.** Computers are paired Hosts; cloud workspaces belong to an explicitly trusted TOB instance. The existing left drawer is shared across both, with Computers and Cloud tabs. Cloud headers expose the same workspace switcher. A guest sees the organization initial/name and “invited channels only”; selecting it shows only current channel grants. Instance domains disambiguate identically named workspaces. The contextual join/pair action stays below the tabs; the directory scrolls between that header and a fixed footer. - **Computer workspaces.** Each paired computer is a Host. - The app stays connected to every paired Host at once. - The Chats list and every chat show one Host at a time. The Chats header has a Slack-style band in the accent colour (a muted accent in dark mode); the list sits on a panel with rounded top corners below it. @@ -34,13 +34,17 @@ The shell is set by [ADR-0211](../../docs/adr/0211-the-mobile-app-has-two-tabs-w - Avatar: the initial tile (default), one of eight pixel portraits from the PersonaBot avatar generator, or a photo cropped square. - Banner: the accent band (default), a solid colour (ten swatches or a typed hex), a two-stop gradient (six presets or typed stops), or a picture under a dark scrim. - A custom colour goes through the accent band's steps, so dark mode mutes it the same way. The ink is white or near-black, whichever reads on every stop; a picture always takes white ink with a soft shadow. -- **Host drawer** switches Hosts. It slides in from the left, covers about 85% of the width and dims the list behind it. - - Like Slack's workspace drawer it has three parts on the `sheet` layer: a fixed "Computers" header, a scrolling list of Hosts, and a fixed footer with **Pair a new computer** (opens the pairing flow) and **Notifications** (opens notification settings), separated from the list by a divider. +- **Workspace drawer** switches between paired Computers and Cloud organization workspaces. It slides in from the left, covers about 85% of the width and dims the list behind it. + - Rounded **Computers / Cloud** tabs are the first row above one scrolling list, with no duplicate title or close button. Opening the drawer selects the current route's tab; switching tabs only changes the list, never the active computer or cloud session. Android uses opaque raised chips; iOS uses the existing glass material with Reduce Transparency, older OS and large-text fallbacks. Tabs expose their selected state to accessibility. + - One contextual plus action sits directly below the tabs, above the scrolling list: Computers opens **Pair a new computer** directly; Cloud opens **Join by link or QR** directly. There is no mixed action chooser or stacked icon group. Organization creation and service configuration live under **Manage cloud services** on the Cloud tab; Notifications stays at the bottom of a fixed footer on both tabs; Cloud service management sits above it. Only the directory scrolls. + - A cloud service is an instance/address; its organization is a cloud workspace; a channel belongs to that organization. An invitation already identifies its service and scope: workspace membership or access to only one channel. The existing preview and acceptance flow keeps this distinction explicit. No separate server-selection step or new authorization store is introduced. - Each Host row has its Computer avatar tile (the same tile as the Host chip; the current Host's tile has an `fg` ring at radius `lg`, concentric with the tile, as Slack marks the current workspace), its name, an online/offline/checking dot and label, then one **count chip** on the right (see Count chip below). It shows **Needs you** when anything waits for the Human, because that matters most; otherwise it shows **Unread**, the count of unread conversations. A ⋯ button at the end, or a long press on the row, opens the Host's menu: Customize (name, avatar and banner), Show this computer, and Unpair, which asks for confirmation. - The Host chip opens it, and so does a swipe right from the left edge of a tab's root screen. The edge swipe is never attached inside a pushed chat, where it stays the system Back. - - Tapping a Host switches to it and closes the drawer. Tapping the backdrop or swiping left closes it. + - Tapping a Host switches to it and closes the drawer. Tapping the backdrop, swiping left or using the accessibility escape gesture closes it. Opening focuses the selected tab. - It takes screen-reader focus when it opens and returns focus to the Host chip when it closes. With Reduce Motion on it appears without sliding. - Android Back closes it. Android draws the same drawer. + - Normal-size rows use a name and a smaller muted address, with one line each. Accessibility sizes may wrap. Status dots and accessible labels retain online/permission context; channel-only guests keep the invited-channel scope in their secondary label. + - Pairing accepts an optional local name using the existing computer appearance store; direct-link pairing can keep the original name, then rename in Customize computer. Cloud import accepts a display name; Manage cloud services can rename it later. These names affect only this phone and never change Host identity, organization names, trusted endpoints or sessions. - **Tabs** are **Chats** and **Activity**. iOS uses `NativeTabs`; Android uses a custom floating bar through the JS tab navigator. There is no search tab. - Activity counts the device's selected Human Attention types, defaulting to pending tool approvals only. Global Settings → Activity count supports multiple types: tool approvals, questions, private input, other pending actions, unread mentions/replies and other unread conversations. Selecting none keeps only the icon. Each unique pending item or unread conversation counts once; handled history is excluded. This device-local choice does not change push preferences or the app icon's push badge. Reads use the existing authenticated `humanAttention` API, including pagination, deduplication and early saturation at 100 for the 99+ display. The observer shares the current Inbox lifecycle, coalesces refreshes, retains same-selection cached counts on failure and discards stale responses after selection or Host changes. Android replaces the inactive icon; iOS uses its native badge. - A chat is pushed above the tabs, so the tab bar hides while it is open. @@ -322,3 +326,9 @@ Every editable field on iOS and Android belongs to a layout that responds to the - Root `KeyboardRoot` supplies the keyboard controller on both native platforms. Modal windows and native form sheets need their own bounded layout; test their actual presented geometry. System resize alone and a keyboard-dismiss button do not establish visibility. Use native keyboard tracking instead of a timer or post-show measurement to reposition forms. - Embedded WebView input keeps native viewport/scroll handling as its keyboard owner; verify the focused web field and web action too. Modern Android WebView resizes its visual viewport for IME overlap ([platform contract](https://developer.android.com/develop/ui/views/layout/webapps/understand-window-insets)). Verify older WebView providers explicitly and check for duplicate insets before adding a native resize wrapper. Remote Browser/Computer text entry must keep the remote caret visible in the resized stage. - Verify each changed input path with the real soft keyboard: open it from a low field, type and move the caret through several lines, switch focus while it stays open, reveal and activate the form action, dismiss/reopen, and verify draft preservation after a failed save. Repeat default/intermediate/maximum system text in light/dark on each available platform. Record unavailable native cases explicitly; source tests and hidden or floating keyboards cannot prove soft-keyboard clearance. + +### Shared drawer title treatment + +The workspace drawer starts with its category tabs. `DrawerHeader` supplies generic bottom `Sheet` headers: a leading semantic title, optional decorative icon, and an independently accessible trailing close action. The iOS title uses a content-sized capsule with native glass on iOS 26; older iOS and Reduce Transparency use an opaque raised capsule. At accessibility text sizes, the title uses an opaque rounded rectangle so multiline text stays within a readable surface. Android keeps a plain left-aligned title on the opaque overlay. The close target is at least the platform touch minimum. Long titles wrap without changing the font scale; subtitles remain outside the capsule. + +Material is a decorative background only: text, focus, hit testing and navigation remain in the existing React Native tree. It must not capture gestures or become another accessibility element. Drawer body and grabber stay opaque and continuous. Header styling does not add dismissal controls to Settings or other native `SheetStack` routes; those retain their established handle/back policy until separately verified. diff --git a/apps/mobile/app/pair.tsx b/apps/mobile/app/pair.tsx index 9bc1de2ba9..0a5f6a8276 100644 --- a/apps/mobile/app/pair.tsx +++ b/apps/mobile/app/pair.tsx @@ -6,6 +6,9 @@ import { useCallback, useRef, useState } from 'react'; import { ActivityIndicator, Platform, Pressable, View } from 'react-native'; import { hostSession } from '../src/host/host-session'; +import { hostLooks } from '../src/host/native-host-look'; +import { HOST_NAME_MAX, hostLookName, withHostName } from '../src/ui/design/host-look'; +import { ConnectionNameField } from '../src/ui/primitives/connection-name-field'; import { nativeCarrier } from '../src/host/native-carrier'; import { pairHost, type PairingFailure } from '../src/host/pairing'; import { mobileTelemetry } from '../src/telemetry/native'; @@ -25,6 +28,7 @@ export default function PairScreen() { const params = useLocalSearchParams<{ p?: string }>(); const [permission, requestPermission] = useCameraPermissions(); const [link, setLink] = useState(''); + const [connectionName, setConnectionName] = useState(''); const [busy, setBusy] = useState(false); const [focused, setFocused] = useState(false); const [error, setError] = useState(); @@ -46,7 +50,11 @@ export default function PairScreen() { method, deviceName: deviceName(), carrier: nativeCarrier(), - save: hostSession.pair, + save: async (host) => { + await hostSession.pair(host); + const name = hostLookName(connectionName); + if (name) hostLooks.set(host.hostId, withHostName(hostLooks.look(host.hostId), name)); + }, telemetry: mobileTelemetry, signal: operation.signal, }); @@ -85,6 +93,12 @@ export default function PairScreen() { >