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
co-authored by Claude Opus 5
parent ffeeb2cdc1
commit 2834f63c8e
45 changed files with 2667 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
using Avalonia.Media;
using Nonemm.Contests;
namespace Nonemm.App;
/// One place decides what colour a station is, so the frame round the callsign
/// box, a row in the check window and a spot on the bandmap cannot disagree.
public static class Verdicts
{
public static readonly IBrush Dupe = new SolidColorBrush(Color.FromRgb(0xC0, 0x39, 0x2B));
public static readonly IBrush NewMultiplier = new SolidColorBrush(Color.FromRgb(0x27, 0xAE, 0x60));
public static readonly IBrush Worth = new SolidColorBrush(Color.FromRgb(0x29, 0x80, 0xB9));
public static readonly IBrush Nothing = new SolidColorBrush(Color.FromRgb(0x7F, 0x8C, 0x8D));
public static IBrush Colour(Verdict? verdict) =>
verdict is null ? Nothing
: verdict.IsDupe ? Dupe
: verdict.IsNewMultiplier ? NewMultiplier
: verdict.Points > 0 ? Worth
: Nothing;
public static string Describe(Verdict? verdict)
{
if (verdict is null)
{
return "";
}
if (verdict.IsDupe)
{
return "dupe";
}
string points = $"{verdict.Points} {(verdict.Points == 1 ? "point" : "points")}";
return verdict.IsNewMultiplier
? $"{points} · new {string.Join(", ", verdict.NewMultipliers.Select(m => m.Value))}"
: points;
}
}