using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; using DodoSSH.Client.App.Platform; namespace DodoSSH.Client.App.Views; /// /// The window's own titlebar, drawn because the design draws one. /// /// /// /// Everything here is a window operation, which is why it is code-behind and not a command on a view model: /// dragging, maximising and closing are properties of the this control happens to be /// inside, and a view model that knew about them would be a view model that could not be tested without one. /// /// /// The window is found by walking up rather than injected, so this control drops into any window — including /// the bare one the layout harness hosts it in, where is simply a different window and /// every handler still has something to act on. /// /// internal sealed partial class TitleBar : UserControl { public TitleBar() { InitializeComponent(); // ◆ A nightly says which one it is, in the one place a person is always looking at. // // The two channels install side by side on purpose, so both windows are on screen at once, both // are called DodoSSH, and both ask for a passphrase the same way. Everything else that // distinguishes them — the Start menu entry, the install directory, the version on the // preferences screen — is somewhere nobody is looking while typing into one of them. // // Set here rather than in the markup so the release build is exactly what the XAML says, and so // the layout harness, which hosts this control directly, measures the shipping string. if (DesktopChannel.IsNightly) { ProductName.Text = "DodoSSH Nightly"; } } private readonly CaptionPresses presses = new(); private Window? Host => TopLevel.GetTopLevel(this) as Window; /// /// Left button only, and only on a press that has not already been handled by something inside the bar — /// otherwise dragging would start from the close button and swallow the click that was meant to close /// the window. /// private void OnDrag(object? sender, PointerPressedEventArgs e) { if (e.Handled || !e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) { return; } // Decided on the press, before the drag would take it: see CaptionPresses. if (presses.IsSecond(e, this)) { OnToggleMaximised(sender, e); e.Handled = true; return; } Host?.BeginMoveDrag(e); } private void OnMinimise(object? sender, RoutedEventArgs e) { if (Host is { } window) { window.WindowState = WindowState.Minimized; } } /// /// Both the button and a double-click on the bar arrive here, which is the convention Windows sets and /// the one people reach for without thinking about it. The double-click comes from /// rather than DoubleTapped; see . /// private void OnToggleMaximised(object? sender, RoutedEventArgs e) { if (Host is not { } window) { return; } window.WindowState = window.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; } private void OnClose(object? sender, RoutedEventArgs e) => Host?.Close(); }