137 lines
4.3 KiB
C#
137 lines
4.3 KiB
C#
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Windows;
|
|
using System.Windows.Threading;
|
|
using TeamsISO.App.Services;
|
|
|
|
namespace TeamsISO.App;
|
|
|
|
/// <summary>
|
|
/// Inline viewer for the daily show-notes file. Reads
|
|
/// <see cref="NotesService.TodayPath"/> on open and polls every 2s while
|
|
/// shown so REST/OSC-driven note appends surface live without the operator
|
|
/// having to click Refresh.
|
|
///
|
|
/// We don't allow editing here — the file is intentionally a one-way log
|
|
/// (operator stamps, post-show review). If someone wants to edit, they
|
|
/// click "Open in editor" and use Notepad.
|
|
/// </summary>
|
|
public partial class NotesWindow : Window
|
|
{
|
|
private readonly DispatcherTimer _refreshTimer;
|
|
private long _lastFileSize = -1;
|
|
private DateTime _lastFileWrite = DateTime.MinValue;
|
|
|
|
public NotesWindow()
|
|
{
|
|
InitializeComponent();
|
|
_refreshTimer = new DispatcherTimer
|
|
{
|
|
Interval = TimeSpan.FromSeconds(2),
|
|
};
|
|
_refreshTimer.Tick += (_, _) => RefreshIfChanged();
|
|
Loaded += (_, _) =>
|
|
{
|
|
DateLine.Text = $"{DateTimeOffset.Now:dddd, MMMM d, yyyy} · {NotesService.TodayPath}";
|
|
ReloadFromDisk();
|
|
_refreshTimer.Start();
|
|
};
|
|
Closed += (_, _) => _refreshTimer.Stop();
|
|
}
|
|
|
|
private void OnClose(object sender, RoutedEventArgs e) => Close();
|
|
|
|
private void OnRefresh(object sender, RoutedEventArgs e) => ReloadFromDisk();
|
|
|
|
/// <summary>
|
|
/// Cheap mtime/size check — only re-reads the file when something changed.
|
|
/// Saves the textbox a flicker on every 2s tick when no notes are being
|
|
/// added. Falls through to a full reload if the file got smaller (operator
|
|
/// might have edited externally).
|
|
/// </summary>
|
|
private void RefreshIfChanged()
|
|
{
|
|
try
|
|
{
|
|
var path = NotesService.TodayPath;
|
|
if (!File.Exists(path)) return;
|
|
var info = new FileInfo(path);
|
|
if (info.Length != _lastFileSize || info.LastWriteTimeUtc != _lastFileWrite)
|
|
ReloadFromDisk();
|
|
}
|
|
catch
|
|
{
|
|
// Disk hiccups shouldn't stop the timer.
|
|
}
|
|
}
|
|
|
|
private void ReloadFromDisk()
|
|
{
|
|
try
|
|
{
|
|
var path = NotesService.TodayPath;
|
|
if (!File.Exists(path))
|
|
{
|
|
NotesText.Text = "No notes yet. Stamp one via the REST or OSC endpoint and refresh.";
|
|
return;
|
|
}
|
|
var info = new FileInfo(path);
|
|
_lastFileSize = info.Length;
|
|
_lastFileWrite = info.LastWriteTimeUtc;
|
|
NotesText.Text = File.ReadAllText(path);
|
|
// Scroll to bottom so the latest stamp is visible — operators are
|
|
// typically reading "what just happened" not "what happened first."
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
Scroller.ScrollToEnd();
|
|
}), DispatcherPriority.Background);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
NotesText.Text = "Couldn't read notes file: " + ex.Message;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Append the input box's text to today's notes file via NotesService,
|
|
/// then clear the box and refresh the view. Bound to the "Add" button +
|
|
/// Enter key in the input. Empty/whitespace input is a no-op.
|
|
/// </summary>
|
|
private void OnAddNote(object sender, RoutedEventArgs e)
|
|
{
|
|
var text = NewNoteBox.Text?.Trim();
|
|
if (string.IsNullOrEmpty(text)) return;
|
|
if (NotesService.Append(text))
|
|
{
|
|
NewNoteBox.Clear();
|
|
ReloadFromDisk();
|
|
NewNoteBox.Focus();
|
|
}
|
|
}
|
|
|
|
/// <summary>Enter key in the input commits the note, same as the Add button.</summary>
|
|
private void OnNewNoteKey(object sender, System.Windows.Input.KeyEventArgs e)
|
|
{
|
|
if (e.Key == System.Windows.Input.Key.Enter)
|
|
{
|
|
OnAddNote(sender, e);
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void OnOpenInEditor(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
Process.Start(new ProcessStartInfo
|
|
{
|
|
FileName = NotesService.TodayPath,
|
|
UseShellExecute = true,
|
|
});
|
|
}
|
|
catch
|
|
{
|
|
// Best-effort; if no .md handler is registered the OS shows its own dialog.
|
|
}
|
|
}
|
|
}
|