Merge branch 'main' into the Android head

Main grew the screens the host-management plan called for — hosts, pins, snippets, logs,
import, teams — plus the ObjectStore and Import projects behind two of them, and moved
WindowsDeviceKeyStore into the desktop head's Platform folder.

Five of those view models landed in a directory this branch had already moved, so they
join the rest in DodoSSH.Client.Shell: git spotted the rename and put them there, and the
namespaces followed. Shell picks up ObjectStore and Import as a result, which the Android
head then gets transitively and will use neither of at first — scoped storage means there
is no ~/.ssh/config to import, and file transfer is out of its first scope.

Desktop suites green at 155 and 64.
This commit is contained in:
2026-07-31 21:03:22 +02:00
199 changed files with 31294 additions and 775 deletions
+33 -9
View File
@@ -5,7 +5,7 @@
x:DataType="vm:MainWindowViewModel">
<!--
Five destinations down the left edge.
Six destinations down the left edge.
One of them — TEAM — reaches a screen that says it is not built. It is in the rail anyway rather than
dropped, and the reasoning is in ShellScreen: the milestones are public, the screen behind it says
@@ -16,6 +16,12 @@
Buttons rather than a TabStrip or a ListBox, for the same reason the vault's category rail is: all three
of those hold the selection themselves, so a click moves the highlight before the shell can decide
anything. Buttons carry no state and cannot disagree with the screen that is showing.
Lit from IsXShowing and not from IsXScreen, which are different questions now that the tab strip spans
every screen. A terminal opened from here leaves Screen on Hosts — deliberately, so closing the tab comes
back — and a rail entry lit while a terminal filled the window would be pointing at a screen that is not
showing. So nothing here is lit at all while a terminal is up: the selected tab already carries that
mark, in the strip, and two "you are here" marks is one too many.
-->
<Border Width="54" Background="{StaticResource Chrome}"
@@ -23,26 +29,44 @@
<DockPanel LastChildFill="False">
<StackPanel DockPanel.Dock="Top" Margin="0,8,0,0">
<Button Classes="flat nav" Content="HOSTS" Classes.active="{Binding IsHostsScreen}"
<Button Classes="flat nav" Content="HOSTS" Classes.active="{Binding IsHostsShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Hosts}"
ToolTip.Tip="Your hosts, and the terminals open on them" />
<Button Classes="flat nav" Content="FILES" Classes.active="{Binding IsTransfersScreen}"
ToolTip.Tip="Your hosts, and what is known about the one you have selected" />
<Button Classes="flat nav" Content="FILES" Classes.active="{Binding IsTransfersShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Transfers}"
ToolTip.Tip="Move files to and from a host over SFTP" />
<Button Classes="flat nav" Content="VAULT" Classes.active="{Binding IsVaultScreen}"
<Button Classes="flat nav" Content="KEYS" Classes.active="{Binding IsVaultShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Vault}"
ToolTip.Tip="SSH keys, stored passwords, and the host keys you have approved" />
<Button Classes="flat nav" Content="TEAM" Classes.active="{Binding IsTeamScreen}"
ToolTip.Tip="Your keychain: SSH keys, stored passwords, and the host keys you have approved" />
<!--
PINS, not HOST KEYS. The rail is 54 pixels wide at mono FontSize 9, which is five characters —
and "pins" is what this codebase calls them everywhere else anyway.
-->
<Button Classes="flat nav" Content="PINS" Classes.active="{Binding IsKnownHostsShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.KnownHosts}"
ToolTip.Tip="Host keys you have approved, and how to withdraw one" />
<!-- SNIPS, for the same five-character reason as PINS above. -->
<Button Classes="flat nav" Content="SNIPS" Classes.active="{Binding IsSnippetsShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Snippets}"
ToolTip.Tip="Commands you have saved, and how to put one into a terminal" />
<!-- LOGS, four characters, so it needs no abbreviating at all. -->
<Button Classes="flat nav" Content="LOGS" Classes.active="{Binding IsLogsShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Logs}"
ToolTip.Tip="What has been connected to, and what has been changed in this keychain" />
<Button Classes="flat nav" Content="TEAM" Classes.active="{Binding IsTeamShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Team}"
ToolTip.Tip="Shared vaults and the people in them. Not built yet — see the screen for what is missing." />
ToolTip.Tip="Shared keychains and the people in them. Not built yet — see the screen for what is missing." />
</StackPanel>
<Button DockPanel.Dock="Bottom" Classes="flat nav" Content="PREFS"
Classes.active="{Binding IsPreferencesScreen}"
Classes.active="{Binding IsPreferencesShowing}"
Command="{Binding ShowScreenCommand}"
CommandParameter="{x:Static vm:ShellScreen.Preferences}"
ToolTip.Tip="Preferences, and this machine's device key" />