Files
Nonemm/src/Nonemm.App/Dialogs/OperatorDialog.axaml.cs
ericek111 654adda080 Keep an operator's windows, colours and recordings
Ctrl+O asks who is at the radio, as it does in N1MM, and the callsign goes on
every contact logged from then on. A multi-operator station changes hands every
few hours, so each operator also keeps what he wants the program to look like:
where the windows sit, the theme, and the folder his recordings are in.

The windows on the screen are stored against the operator leaving, before the
dialog opens, and the operator taking over gets his own back. A window he opens
later is placed as it appears. An operator who is new to the list starts with
whatever is on the screen.

Nothing plays the recordings yet, so the folder is stored and waits on voice
keying. {OPERATOR} in a message sends the callsign.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
2026-08-31 22:28:18 +00:00

103 lines
3.6 KiB
C#

using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Nonemm.App.Configuration;
namespace Nonemm.App.Dialogs;
/// What the operator dialog closed with: the operator to change to, or the one
/// to drop from the list.
public sealed record OperatorChoice(StoredOperator Operator, bool IsRemoval);
/// N1MM's Ctrl+O: who is at the radio now. It closes with the operator to
/// change to, or with null when nothing is to change. An operator whose
/// callsign is not in the list yet is made by typing it.
public sealed partial class OperatorDialog : Window
{
private readonly IReadOnlyList<StoredOperator> known;
public OperatorDialog(Settings settings)
{
known = settings.Operators;
InitializeComponent();
KnownBox.ItemsSource = known.Select(o => o.Callsign).ToList();
CallBox.Text = settings.CurrentOperator;
WavBox.Text = Find(settings.CurrentOperator)?.WavPath ?? "";
ShowWhatIsKept();
// the callsign is all most operators type here, so the cursor starts in
// it and Enter closes the dialog
Opened += (_, _) =>
{
CallBox.Focus();
// the operator taking over types his own callsign over the one
// leaving rather than clearing the box first
CallBox.SelectAll();
};
}
/// The operator as the dialog leaves him: the callsign typed, keeping
/// whatever was stored for him before.
private StoredOperator Picked
{
get
{
string callsign = (CallBox.Text ?? "").Trim().ToUpperInvariant();
StoredOperator stored = Find(callsign) ?? new StoredOperator();
return stored with { Callsign = callsign, WavPath = (WavBox.Text ?? "").Trim() };
}
}
private StoredOperator? Find(string callsign) =>
known.FirstOrDefault(o => string.Equals(o.Callsign, callsign.Trim(), StringComparison.OrdinalIgnoreCase));
private void OnPickedKnown(object? sender, SelectionChangedEventArgs e)
{
if (KnownBox.SelectedItem is not string callsign)
{
return;
}
CallBox.Text = callsign;
WavBox.Text = Find(callsign)?.WavPath ?? "";
ShowWhatIsKept();
}
private void ShowWhatIsKept()
{
StoredOperator? stored = Find(CallBox.Text ?? "");
AboutText.Text = stored is null
? "A new operator: the windows and colours on the screen now become his."
: $"{stored.Windows.Count} window positions kept"
+ (stored.Theme.Length > 0 ? $", {stored.Theme} colours" : ", the colours as they are");
}
private async void OnBrowseWav(object? sender, RoutedEventArgs e)
{
IReadOnlyList<IStorageFolder> picked = await StorageProvider.OpenFolderPickerAsync(
new FolderPickerOpenOptions { Title = "The operator's recordings", AllowMultiple = false });
if (picked.Count > 0)
{
WavBox.Text = picked[0].Path.LocalPath;
}
}
private void OnOk(object? sender, RoutedEventArgs e)
{
if (Picked.Callsign.Length > 0)
{
Close(new OperatorChoice(Picked, IsRemoval: false));
}
}
/// Drops the operator from the list. The contacts he logged keep his
/// callsign: they are in the log, not in the settings.
private void OnRemove(object? sender, RoutedEventArgs e)
{
if (Find(CallBox.Text ?? "") is { } stored)
{
Close(new OperatorChoice(stored, IsRemoval: true));
}
}
private void OnCancel(object? sender, RoutedEventArgs e) => Close(null);
}