using Avalonia.Media; using Nonemm.App.Theming; using Nonemm.Network; namespace Nonemm.App.Windows; /// One line of the network status window, in N1MM's columns. The station /// itself holds the raw values; this turns them into the text of a cell. public sealed class StationRow { private readonly NetworkedStation station; private readonly DateTime now; public StationRow(NetworkedStation station, DateTime now) { this.station = station; this.now = now; } public NetworkedStation Station => station; public string Computer => station.StationNumber > 0 ? $"{station.ComputerName} ({station.StationNumber})" : station.ComputerName; public string IpAddress => station.Port > 0 && station.Address.Length > 0 ? $"{station.Address}:{station.Port}" : station.Address; /// The frequency this station is passing contacts on, and who is on it. public string Pass => station.PassFrequency.Hertz > 0 ? $"{station.PassFrequency.Kilohertz:0.0} {station.PassCall}".TrimEnd() : ""; /// Run or search and pounce, which is N1MM's Run column. public string Run => station.IsRunning ? "Run" : "S&P"; public string Last10 => station.Last10 > 0 ? station.Last10.ToString() : ""; public string Last100 => station.Last100 > 0 ? station.Last100.ToString() : ""; public string Freq => station.Frequency.Hertz > 0 ? $"{station.Frequency.Kilohertz:0.0}" : ""; public string Op => station.Operator; /// The last message this station sent, and TX while it is transmitting. /// Two stations keying at once is what an operator watches this column for. public string Msg => station.IsTransmitting ? $"TX {station.LastMessage}".TrimEnd() : station.LastMessage; /// Whether this program can write to the station. N1MM prints OK and so /// does this. public string Send => station.IsMine ? "" : station.IsConnected ? "OK" : "no"; /// Whether anything is arriving. A station that has said nothing for a /// while reads as how long ago that was, because a connection that stands /// open is not the same as a station that is still there. public string Receive { get { if (station.IsMine) { return ""; } TimeSpan since = now - station.LastHeardUtc; return since < StationLink.Patience ? "OK" : Ago(since); } } public string Band => station.Band?.Name ?? ""; /// Run1 or Run2, which N1MM heads `R/M`. public string RunMult => station.IsRun2 ? "Run2" : "Run1"; public string Mode => station.Mode?.Name ?? ""; /// The resync columns. N1MM counts blocks of an hour, which is why they /// say hours. public string InProgress => station.IsResyncing ? "yes" : ""; public string Status => station.ResyncStatus; public string HoursOk => station.HoursOk > 0 ? station.HoursOk.ToString() : ""; public string HoursFixed => station.HoursFixed > 0 ? station.HoursFixed.ToString() : ""; public string HoursFailed => station.HoursFailed > 0 ? station.HoursFailed.ToString() : ""; /// Red for a station that is not talking, and for the version mismatch that /// leaves everything else looking right. Every other row takes the theme's /// own text colour: the grid reuses its rows, so a row that was red has to /// be painted back. public IBrush Colour => !station.IsMine && (station.Refused.Length > 0 || !station.IsConnected) ? Themes.Brush(Themes.Current.BadBackground) : Themes.Brush(Themes.Current.FieldForeground); /// How long ago, in the shortest form that says it. private static string Ago(TimeSpan since) => since switch { { TotalMinutes: < 1 } => $"{since.Seconds} s", { TotalHours: < 1 } => $"{since.Minutes} min", _ => "over an hour", }; }