Merge main into the phone connections branch
ci / build and test (push) Canceled after 46s
ci / android head (push) Canceled after 0s
ci / api image (push) Canceled after 0s

Main had already taken this branch's first two commits, so what merged is the
Connections work against three things that landed beside it. Four of the six
conflicts were prose about arrangements both sides changed; two were real.

**The phone hub gained a Teams row while this branch was moving the keychain
onto it.** Both are additions to `IsMoreSurface` and both belong: teams because
the desktop reaches them from its rail and the phone through the hub, the
keychain because a bottom bar is for the places a session moves between. The
membership test, the back gesture's first case and the hub's own arithmetic all
take the union. The distinction is now written down rather than implied — teams
is the design's count plus one, and the keychain is the only rearrangement of
it: the bar lost a slot to gain that row.

**`ConnectAndAnnounceAsync` was the real one.** Main gave it
`RememberTypedPasswordAsync`, which binds the password that just worked to the
host it worked on; this branch had replaced the `HostRowViewModel` that method
needs with a four-field `ConnectionTarget`. Keeping both meant deciding what a
manual connection does with a password that succeeded, and the answer was
already written on the screen it is typed into: nothing. There is no item to
bind a credential to and none to bind it on, and that path saves nothing by
design.

So `ConnectionTarget` carries the row again — as a nullable, in place of the
host id it had, with `HostId` derived from it. Two things read it and both are
things that can only be done to a keychain item rather than to an address:
naming the log entry, and keeping the password. Null is not missing data there;
it is the whole of what makes the manual path different, and having one field
rather than two keeps "was this a keychain host" a question with one answer.

The desktop's rail lost SFTP and S3 to the tab strip on main, so the README's
"a rail with nine slots has room" was true when it was written this afternoon
and is not now. It says the room rather than the number.

Phase 11's four new device checks and main's Phase 12 on teams were the same
conflict twice — two appends to the end of one file — and both are kept.

Verified after resolving: the solution builds, the Android head builds clean,
and 837 tests pass across the seven client suites, including main's own additions
(233 shell, 79 layout, 240 domain, 118 sync, 54 session, 74 terminal, 39
storage).
This commit is contained in:
2026-08-03 15:35:49 +02:00
88 changed files with 9866 additions and 1707 deletions
+4 -2
View File
@@ -489,7 +489,8 @@ go at 360dp:
The nav rail's eight destinations became four. Pins, snippets, logs, import and teams are not built here:
import has no meaning under scoped storage, and the other four are list screens whose view models already
exist — they are additive rather than structural.
exist — they are additive rather than structural. *(Snippets, logs and teams have since been built, behind
MORE. Pins and import have not, and import still cannot be.)*
**Superseded by v2.** A second design — *DodoSSH Android v2* — is what this head now draws, and it took
the "additive rather than structural" claim at its word: snippets, logs, SFTP and S3 are built, over the
@@ -552,7 +553,8 @@ What is left, in the order it matters:
source, which is the decision recorded above and the obvious next piece of work.
- **Editors.** There is no host editor and no keychain item editor on the phone, so both are create-on-
desktop-and-sync. That is why the v2 design's `+` buttons on HOSTS and on the keychain are not drawn.
- **Pins, teams and import**, which v2 does not draw either.
- **Pins and import**, which v2 does not draw either. Teams *is* drawn, behind MORE — it was the one of
the three whose view model needed nothing new on the phone, because none of that screen is vault content.
- **The App Link upgrade**, unchanged from step 5.
---