diff --git a/README.md b/README.md index 0373ea2..d180afc 100644 --- a/README.md +++ b/README.md @@ -553,6 +553,17 @@ does not draw is anything that takes access away: REMOVE and WITHDRAW KEY act on irreversible revocation under a thumb with its explanation in a tooltip nothing can show is the wrong trade. +**On a surface wider than 600dp it lays itself out like the desktop.** A tablet, an unfolded foldable, a +phone in landscape or a freeform window gets a nav rail down the left carrying every destination at once, +and the three-entry bottom bar stands down with the SETTINGS hub it led to — a hub is an extra tap between +you and a screen there is visibly room for. Below that width nothing changes. The one number is Android's +own boundary between a compact window and a medium one, measured in the density-independent units Avalonia +lays out in. + +What it does *not* yet do is use the extra width inside a screen: the host list is still one column at any +size. Two columns needs the row model to change — the list is headings and hosts in one sequence, and a +heading has to span — which is shared with the desktop and is its own piece of work. + **Port forwarding is not built anywhere**, and the phone's More screen says so in a paragraph rather than leaving a gap. The v2 design draws a whole screen for it; nothing in the SSH layer forwards anything, so every control on that screen would have had no effect. See diff --git a/docs/manual-checks.md b/docs/manual-checks.md index 630b734..3fe4abf 100644 --- a/docs/manual-checks.md +++ b/docs/manual-checks.md @@ -917,7 +917,37 @@ repository; see `docs/platform-flags.md`. Get the stack with `adb logcat -d -b c Every check below assumes this one passed, and none of them can be reached if it did not. -### 8.1 The + is reachable and is not covering anything +### 8.1 A wide surface draws the rail, and a narrow one draws the bar · **needs a tablet, a foldable or a resizable window** + +Open the application on something at least 600dp wide — a tablet, an unfolded foldable, a phone in +landscape, or a freeform window dragged wide. + +**Pass:** a rail down the left edge carrying Hosts, Connections, Keychain, Snippets, SFTP, S3, Logs, Vaults +and Preferences, with Preferences at the foot. **No bar across the bottom.** The header with the vault's +name, the sync light and LOCK is up, and stays up on every one of those screens rather than disappearing on +the keychain the way it does on a phone. + +Now make it narrow again — fold it, rotate it, drag the window in. + +**Pass:** the rail goes, the bottom bar comes back with its three entries, and the screens behind SETTINGS +have their back arrows again. + +Go to SETTINGS on the narrow surface, then widen it without touching anything else. + +**Pass:** it lands on Hosts rather than sitting on the hub. The hub is a list of the destinations the rail +now carries, so staying there would be a menu of things visible beside it. + +On the wide surface, open the keychain and press the system back gesture. + +**Pass:** Hosts. Not the hub — that screen is not drawn here, and backing into it would strand somebody on +a surface with no way off it but a second back. + +**Failure means:** a rail *and* a bottom bar at once is `ShowsRail` and `ShowsBottomBar` no longer being +each other's opposite. A back arrow on a wide surface leads to a screen the layout removed. And a bar that +never becomes a rail is the resize handler having gone back to returning early when the keyboard is +closed — which is how a foldable would open to a phone layout until somebody typed something. + +### 8.2 The + is reachable and is not covering anything Look at the bottom right of the host list with no host selected. @@ -930,7 +960,7 @@ and hold a host so the connect bar rises. harness would catch it if it could run — its only fit rule is containment inside the window, never overlap between two controls, so a button sitting squarely on top of CONNECT reports clean. -### 8.2 The sheet says what each choice does +### 8.3 The sheet says what each choice does Tap the +. @@ -941,7 +971,7 @@ with a sentence under it, and CANCEL. The scrim darkens the list. not a decision, and navigating away is a fine way to answer it. Compare the changed-host-key screen, which must offer no way out but BACK. -### 8.3 The sheet is dismissible three ways +### 8.4 The sheet is dismissible three ways Tap the scrim. Reopen, tap CANCEL. Reopen, use the system back gesture. @@ -950,7 +980,7 @@ Tap the scrim. Reopen, tap CANCEL. Reopen, use the system back gesture. **Failure means:** back is being handled by the screen switch rather than by the guard above it, and the gesture has left HOSTS instead of closing the sheet. -### 8.4 An empty port box says what it will dial +### 8.5 An empty port box says what it will dial Add a group with a default port of 2222, then tap + → New host and choose that group in the GROUP picker. @@ -960,7 +990,7 @@ chosen. The username box behaves the same way. **Failure means:** the editor loaded a resolved value into the box instead of a placeholder behind it — saving would then pin 2222 onto the host, and changing the group later would leave that host behind. -### 8.5 A host created that way inherits rather than copies +### 8.6 A host created that way inherits rather than copies Save that host, then edit the group's default port to 2200 and look at the host's row. @@ -968,7 +998,7 @@ Save that host, then edit the group's default port to 2200 and look at the host' **Failure means:** the port was copied at creation and the group is a one-shot template. -### 8.6 Filing a host into a group does not silently pin its password +### 8.7 Filing a host into a group does not silently pin its password Add a group with a default SSH key. Add a host with no group and leave AUTHENTICATION on **Password (ask each time)**. Save. Now edit it and choose the group. @@ -979,7 +1009,7 @@ each time)**. Save. Now edit it and choose the group. **Failure means:** the picker's "Password (ask each time)" was written as a decision when it was only the absence of one, and this host will never use the fleet's key. -### 8.7 A host can still refuse its group's key +### 8.8 A host can still refuse its group's key On that same host, set AUTHENTICATION back to **Password (ask each time)** and save. @@ -987,7 +1017,7 @@ On that same host, set AUTHENTICATION back to **Password (ask each time)** and s **Failure means:** the fourth state has no storage and the host is inheriting whatever the group says. -### 8.8 Back closes the topmost thing, one at a time +### 8.9 Back closes the topmost thing, one at a time Tap + → New host, then use the back gesture. @@ -998,7 +1028,7 @@ Repeat with the group menu: tap the `⋯` on a group heading, then back. **Pass:** the menu closes and nothing is armed behind it — no editor, no question, no move panel. -### 8.9 Every target is a thumb's size +### 8.10 Every target is a thumb's size Walk both sheets' rows, the editor's fields, both pickers, the checkbox and the four buttons. @@ -1007,7 +1037,7 @@ Walk both sheets' rows, the editor's fields, both pickers, the checkbox and the **Failure means:** a control took its size from its glyph. The desktop suite's only tap-target assertion has a floor of 20 pixels — set for a mouse — so copying it here would certify a target no thumb can hit. -### 8.10 The group menu names its group, and the heading still fits +### 8.11 The group menu names its group, and the heading still fits Needs a vault with at least one group holding a host. On HOSTS, look at the group's heading row first. @@ -1024,7 +1054,7 @@ scrim closes it. **Failure means:** if the name is missing, the sheet is bound to the wrong thing; the whole point of naming it is that the heading it was raised from may have scrolled away under the scrim. -### 8.11 Deleting a group asks the second question +### 8.12 Deleting a group asks the second question `⋯` → Delete on a group with at least two hosts filed under it. @@ -1041,7 +1071,7 @@ Now tick it and press DELETE. **Pass:** the group and its hosts are gone. Untick it on a third group and the hosts survive under UNGROUPED. -### 8.12 Moving a group names the shelf · **needs a second writable vault** +### 8.13 Moving a group names the shelf · **needs a second writable vault** `⋯` → Move to another vault. @@ -1060,7 +1090,7 @@ selection, which this head never sets. That is the exact failure the header-aime With only one writable vault, the entry answers on the status line instead and no panel opens. That is the intended answer, not a failure. -### 8.13 DELETE under a host is not beside EDIT +### 8.14 DELETE under a host is not beside EDIT Press and hold a host so the connect bar rises. @@ -1076,7 +1106,7 @@ puts them back with the host still there. the second press landing on whatever the list rebuilt underneath. -### 8.14 A tap connects, and a long press is what raises the bar · **the one worth the most care** +### 8.15 A tap connects, and a long press is what raises the bar · **the one worth the most care** On a host bound to a key or a stored credential — one that needs nothing typed — tap the row once. @@ -1100,7 +1130,7 @@ a password host with an empty box is worse: the connection fails somewhere the u press that connects means `held` in `HostsScreen.axaml.cs` is not suppressing the `Tapped` that follows a hold, so one touch fires both gestures. -### 8.15 The pencil in the header edits the chosen host +### 8.16 The pencil in the header edits the chosen host With a host chosen — by a tap that connected, or by a long press — look at the header beside LOCK. @@ -1337,7 +1367,7 @@ Tapping the hand-typed one puts its address back in the box on this screen and l **Failure means:** if the hand-typed one navigates to HOSTS, the log entry is carrying a host id it should not have. If the password came back, something is storing it — it never was. And if the keychain one arrives with the host selected but **no bar**, `ConnectToRecent` is setting the selection rather than opening the -pane: since 8.14 a selection alone raises nothing, so that is a screen with nothing to press. +pane: since 8.15 a selection alone raises nothing, so that is a screen with nothing to press. ### 11.9 Settings holds the keychain, and back walks out of it diff --git a/src/DodoSSH.Client.Android/Views/FilesScreen.axaml b/src/DodoSSH.Client.Android/Views/FilesScreen.axaml index bf43a61..6702fc7 100644 --- a/src/DodoSSH.Client.Android/Views/FilesScreen.axaml +++ b/src/DodoSSH.Client.Android/Views/FilesScreen.axaml @@ -52,7 +52,13 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/DodoSSH.Client.Android/Views/PhoneRail.axaml.cs b/src/DodoSSH.Client.Android/Views/PhoneRail.axaml.cs new file mode 100644 index 0000000..8d0c196 --- /dev/null +++ b/src/DodoSSH.Client.Android/Views/PhoneRail.axaml.cs @@ -0,0 +1,15 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace DodoSSH.Client.Android.Views; + +/// The destinations down the left edge, on a surface too wide to be a phone. +/// +/// No code at all, unlike every other view on this head: it is buttons bound to commands the shell already +/// has, and the one thing that decides whether it is drawn — the width — belongs to PhoneShell, +/// which is the control that measures the surface. +/// +internal sealed partial class PhoneRail : UserControl +{ + public PhoneRail() => AvaloniaXamlLoader.Load(this); +} diff --git a/src/DodoSSH.Client.Android/Views/PhoneShell.axaml b/src/DodoSSH.Client.Android/Views/PhoneShell.axaml index 1355bc3..8c8e399 100644 --- a/src/DodoSSH.Client.Android/Views/PhoneShell.axaml +++ b/src/DodoSSH.Client.Android/Views/PhoneShell.axaml @@ -52,26 +52,52 @@ - + + + + + + - + + BorderThickness="0,0,0,1" Padding="14,0" Height="56"> +