Add the Avalonia application and the station network

The entry window types contacts and colours them as they are typed; the log,
check, bandmap, score and packet windows read the same session. Contacts are
shared with the other stations of a multi-operator entry in N1MM's contact
message, so an N1MM station on the same network sees them too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik
2026-08-27 10:56:35 +00:00
parent ffeeb2cdc1
commit 2834f63c8e
45 changed files with 2667 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
using Nonemm.Core;
namespace Nonemm.App.Windows;
/// The contacts of the contest in progress, newest last.
public sealed partial class LogWindow : RefreshableWindow
{
private readonly AppSession session;
public LogWindow(AppSession session)
{
this.session = session;
InitializeComponent();
Refresh();
}
public override void Refresh()
{
if (session.Logging is null)
{
Rows.ItemsSource = Array.Empty<LogRow>();
SummaryText.Text = "no contest is open";
return;
}
List<LogRow> rows = session.Logging.Log.Qsos
.Select(q => new LogRow(q, VerdictFor(q)))
.ToList();
Rows.ItemsSource = rows;
if (rows.Count > 0)
{
Rows.ScrollIntoView(rows[^1], null);
}
SummaryText.Text =
$"{session.Logging.Log.Tally.Qsos} contacts · {session.Logging.Log.Tally.Points} points · " +
$"{session.Logging.Log.Tally.TotalMultipliers} multipliers · score {session.Logging.Log.TotalScore:N0}";
}
/// A logged contact is coloured by what it turned out to be worth, not by
/// judging it again as if it were new.
private static Contests.Verdict VerdictFor(Qso qso) =>
new(
IsDupe: false,
Points: qso.Points,
NewMultipliers: qso.IsMultiplier1 || qso.IsMultiplier2 || qso.IsMultiplier3
? [new Contests.Multiplier(1, "", "")]
: []);
}