Add the Info window, following N1MM's source
The window shows the operator, the call-frame spot, country, bearing and sun lines, the WWV line and a message area. It draws both rate graphs against the goals and shows the QSO timer (seven modes), the band timer, the band-change count and the Run/Mult box. Goals use N1MM's `dhh goal` file format and its Import Goals rules, including statistics and CSV files. Logic that does not need the UI is in Nonemm.Contests (Goals, QsoTimer, RateBars) and Nonemm.Session (InfoLines), with tests. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Nonemm.Contests;
|
||||
|
||||
namespace Nonemm.App.Dialogs;
|
||||
|
||||
/// N1MM's goals editor, as the text the goals are kept in. It returns the
|
||||
/// goals in `Goals.ToText` form, or null when cancelled.
|
||||
public sealed partial class GoalsDialog : Window
|
||||
{
|
||||
private readonly string exportFolder;
|
||||
|
||||
public GoalsDialog(string goals, string exportFolder)
|
||||
{
|
||||
this.exportFolder = exportFolder;
|
||||
InitializeComponent();
|
||||
GoalsBox.Text = goals;
|
||||
}
|
||||
|
||||
private void OnOk(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Checked() is { } text)
|
||||
{
|
||||
Close(text);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancel(object? sender, RoutedEventArgs e) => Close(null);
|
||||
|
||||
/// Writes the goals to a file N1MM's Import Goals reads, keeping the
|
||||
/// dialog open.
|
||||
private async void OnExport(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Checked() is not { } text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
IStorageFile? file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
Title = "Export goals",
|
||||
SuggestedFileName = "goals.txt",
|
||||
SuggestedStartLocation = await StorageProvider.TryGetFolderFromPathAsync(exportFolder),
|
||||
});
|
||||
if (file?.TryGetLocalPath() is not { } path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
await File.WriteAllTextAsync(path, text);
|
||||
ProblemText.Text = $"{Path.GetFileName(path)} written.";
|
||||
}
|
||||
catch (IOException problem)
|
||||
{
|
||||
ProblemText.Text = $"could not write {path}: {problem.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private string? Checked()
|
||||
{
|
||||
try
|
||||
{
|
||||
ProblemText.Text = "";
|
||||
return Goals.Parse(GoalsBox.Text ?? "").ToText();
|
||||
}
|
||||
catch (FormatException problem)
|
||||
{
|
||||
ProblemText.Text = problem.Message;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user