The generic name only resolves through fontconfig, so on Windows the windows fell back to the proportional default. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
112 lines
3.7 KiB
C#
112 lines
3.7 KiB
C#
using Nonemm.App.Theming;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Input;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Media;
|
|
using Avalonia.Threading;
|
|
using Nonemm.Core;
|
|
using Nonemm.Session;
|
|
|
|
namespace Nonemm.App.Windows;
|
|
|
|
/// What is left to work, a column per band: the multipliers at the top of each
|
|
/// column, then the stations that are only points. Clicking one puts the radio
|
|
/// there with the call in the entry window, the same as clicking a spot on the
|
|
/// bandmap.
|
|
public sealed partial class AvailableWindow : RefreshableWindow
|
|
{
|
|
private readonly AppSession session;
|
|
private readonly Action<Frequency, string> tune;
|
|
|
|
public AvailableWindow(AppSession session, Action<Frequency, string> tune)
|
|
{
|
|
this.session = session;
|
|
this.tune = tune;
|
|
InitializeComponent();
|
|
MultsOnlyBox.IsCheckedChanged += (_, _) => Refresh();
|
|
session.Bandmap.Changed += (_, _) => Dispatcher.UIThread.Post(Refresh);
|
|
Refresh();
|
|
}
|
|
|
|
public override void Refresh()
|
|
{
|
|
Columns.Children.Clear();
|
|
Columns.ColumnDefinitions.Clear();
|
|
if (session.Available is null)
|
|
{
|
|
StatusText.Text = "no contest is open";
|
|
return;
|
|
}
|
|
|
|
session.Bandmap.DropOlderThan(DateTime.UtcNow);
|
|
bool multsOnly = MultsOnlyBox.IsChecked == true;
|
|
List<AvailableStation> stations = session.Available.All()
|
|
.Where(s => !multsOnly || s.IsMultiplier)
|
|
.ToList();
|
|
List<Band> bands = stations
|
|
.Select(s => s.Band)
|
|
.Distinct()
|
|
.OrderBy(b => b.Low.Hertz)
|
|
.ToList();
|
|
|
|
int at = 0;
|
|
foreach (Band band in bands)
|
|
{
|
|
Columns.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));
|
|
Control column = BuildColumn(band, stations.Where(s => s.Band == band).ToList());
|
|
Grid.SetColumn(column, at++);
|
|
Columns.Children.Add(column);
|
|
}
|
|
|
|
int mults = stations.Count(s => s.IsMultiplier);
|
|
StatusText.Text = stations.Count == 0
|
|
? "nothing spotted that is not worked"
|
|
: $"{stations.Count} to work · {mults} multipliers";
|
|
}
|
|
|
|
private Control BuildColumn(Band band, IReadOnlyList<AvailableStation> stations)
|
|
{
|
|
StackPanel panel = new() { Margin = new Avalonia.Thickness(0, 0, 8, 0) };
|
|
panel.Children.Add(new TextBlock
|
|
{
|
|
Text = $"{band.Name} {stations.Count}",
|
|
FontSize = 11,
|
|
Opacity = 0.7,
|
|
Margin = new Avalonia.Thickness(0, 0, 0, 4),
|
|
});
|
|
foreach (AvailableStation station in stations)
|
|
{
|
|
panel.Children.Add(Row(station));
|
|
}
|
|
return panel;
|
|
}
|
|
|
|
private Control Row(AvailableStation station)
|
|
{
|
|
TextBlock text = new()
|
|
{
|
|
Text = Label(station),
|
|
FontFamily = Fonts.Mono,
|
|
FontSize = 13,
|
|
Foreground = Verdicts.Colour(station.Verdict),
|
|
HorizontalAlignment = HorizontalAlignment.Left,
|
|
Cursor = new Cursor(StandardCursorType.Hand),
|
|
};
|
|
ToolTip.SetTip(text, Tip(station));
|
|
text.PointerPressed += (_, _) => tune(station.Spot.Frequency, station.Spot.Call.Text);
|
|
return text;
|
|
}
|
|
|
|
private static string Label(AvailableStation station)
|
|
{
|
|
string call = $"{station.Spot.Frequency.Kilohertz,9:0.0} {station.Spot.Call.Text}";
|
|
return station.IsMultiplier ? $"{call} · {station.MultiplierText}" : call;
|
|
}
|
|
|
|
private static string Tip(AvailableStation station)
|
|
{
|
|
string who = station.Spot.Spotter.Length > 0 ? $" de {station.Spot.Spotter}" : "";
|
|
return $"{Verdicts.Describe(station.Verdict)}{who}";
|
|
}
|
|
}
|