using Microsoft.AspNetCore.Components;
namespace AIStudio.Components;
///
/// Shows how long something has been running, counting up every second.
///
///
/// A model which thinks for minutes shows nothing for just as long, and the time is what tells the user
/// that it still works. The component owns its timer and renders only itself once a second, not the
/// page around it: an assistant would otherwise render its entire form every second.
///
public partial class ElapsedTime : MSGComponentBase
{
private static readonly TimeSpan TICK_INTERVAL = TimeSpan.FromSeconds(1);
///
/// When it started.
///
[Parameter]
public DateTimeOffset Start { get; set; }
/// Stops counting.
private readonly CancellationTokenSource tickCancellation = new();
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
this.TickAsync(this.tickCancellation.Token).Observe($"{nameof(ElapsedTime)}: counting the elapsed time");
}
#endregion
#region Overrides of MSGComponentBase
protected override void DisposeResources()
{
this.tickCancellation.Cancel();
this.tickCancellation.Dispose();
base.DisposeResources();
}
#endregion
///
/// Writes a time span as minutes and seconds, and with the hours in front from the first hour on.
///
/// The time span; a negative one, e.g., after the clock was set back, counts as none.
/// The time span, such as 4:07 or 1:02:09.
internal static string Format(TimeSpan elapsed)
{
if (elapsed < TimeSpan.Zero)
elapsed = TimeSpan.Zero;
var hours = (int)elapsed.TotalHours;
return hours > 0
? $"{hours}:{elapsed.Minutes:00}:{elapsed.Seconds:00}"
: $"{elapsed.Minutes}:{elapsed.Seconds:00}";
}
private async Task TickAsync(CancellationToken token)
{
using var timer = new PeriodicTimer(TICK_INTERVAL);
try
{
while (await timer.WaitForNextTickAsync(token))
await this.InvokeAsync(this.StateHasChanged);
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
}
}
}