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
@@ -0,0 +1,28 @@
using Avalonia.Controls;
using Avalonia.Input;
using DodoSSH.Client.Shell.ViewModels;
namespace DodoSSH.Client.App.Views;
/// <summary>
/// What has been connected to, and what has been changed.
/// </summary>
/// <remarks>
/// Its data context is a <c>LogsViewModel</c>, a screen-scoped wrapper over the open session. Both logs are
/// ordinary synced keychain items; nothing about them is local.
/// </remarks>
internal sealed partial class LogsScreen : UserControl
{
public LogsScreen() => InitializeComponent();
/// <summary>Where the keyboard lands when this screen is the one showing.</summary>
/// <remarks>
/// Whichever list is on screen, because this screen has no filter box and a collapsed control cannot
/// take focus — <c>Focus()</c> on one is a no-op that nothing replays when it is revealed. The lists are
/// focusable explicitly for the same reason the host list is: Avalonia leaves focus to the items, and an
/// empty list has none.
/// </remarks>
internal IInputElement KeyboardTarget =>
DataContext is LogsViewModel { ShowsActivity: true } ? ActivityList : ConnectionList;
}