From 60d1263677b7be197da7fe55fdb45227f37c08d4 Mon Sep 17 00:00:00 2001 From: Alex Hedley Date: Tue, 26 Sep 2023 08:26:46 +0100 Subject: [PATCH] #27 WIP Timer/Stopwatch --- src/Utility.Test/StopwatchTest.cs | 36 ++++++ src/Utility.Test/TimerControlTest.cs | 34 ++++++ .../Components/Stopwatch/Stopwatch.razor | 109 ++++++++++++++++++ .../Components/Stopwatch/Stopwatch.razor.css | 0 .../TimerControl/TimerControl.razor | 109 ++++++++++++++++++ .../TimerControl/TimerControl.razor.css | 0 src/Utility/Pages/TimerStopwatch.razor | 12 ++ src/Utility/Pages/TimerStopwatch.razor.css | 0 src/Utility/Shared/NavMenu.razor | 5 + 9 files changed, 305 insertions(+) create mode 100644 src/Utility.Test/StopwatchTest.cs create mode 100644 src/Utility.Test/TimerControlTest.cs create mode 100644 src/Utility/Components/Stopwatch/Stopwatch.razor create mode 100644 src/Utility/Components/Stopwatch/Stopwatch.razor.css create mode 100644 src/Utility/Components/TimerControl/TimerControl.razor create mode 100644 src/Utility/Components/TimerControl/TimerControl.razor.css create mode 100644 src/Utility/Pages/TimerStopwatch.razor create mode 100644 src/Utility/Pages/TimerStopwatch.razor.css diff --git a/src/Utility.Test/StopwatchTest.cs b/src/Utility.Test/StopwatchTest.cs new file mode 100644 index 0000000..7061036 --- /dev/null +++ b/src/Utility.Test/StopwatchTest.cs @@ -0,0 +1,36 @@ +using Bunit; +using Xunit; + +using Utility.Components.Stopwatch; + +namespace Utility.Test; + +public class StopwatchTest : TestContext +{ + public StopwatchTest() {} + + // [Fact] + public void StopwatchShouldStart() + { + string input = ""; + string expectedInput = ""; + + + var cut = RenderComponent(parameters => parameters + .Add(p => p.Input, input) + ); + + cut.FindAll("button")[0].Click(); + // string markup = ""; + // cut.FindAll("input")[1].MarkupMatches(markup); + + Stopwatch stopwatch = cut.Instance; + Assert.Equal(stopwatch.Input, input); + } + + // [Fact] + public void StopwatchShouldStop() + { + + } +} \ No newline at end of file diff --git a/src/Utility.Test/TimerControlTest.cs b/src/Utility.Test/TimerControlTest.cs new file mode 100644 index 0000000..d3b6433 --- /dev/null +++ b/src/Utility.Test/TimerControlTest.cs @@ -0,0 +1,34 @@ +using Bunit; +using Xunit; + +using Utility.Components.TimerControl; + +namespace Utility.Test; + +public class TimerControlTest : TestContext +{ + public TimerControlTest() {} + + // [Fact] + public void TimerControlShouldStart() + { + string input = "5m 00s"; + string expectedInput = ""; + var cut = RenderComponent(parameters => parameters + .Add(p => p.Input, input) + ); + + cut.FindAll("button")[0].Click(); + // string markup = ""; + // cut.FindAll("input")[1].MarkupMatches(markup); + + TimerControl timerControl = cut.Instance; + Assert.Equal(timerControl.Input, input); + } + + // [Fact] + public void TimerControlShouldStop() + { + + } +} \ No newline at end of file diff --git a/src/Utility/Components/Stopwatch/Stopwatch.razor b/src/Utility/Components/Stopwatch/Stopwatch.razor new file mode 100644 index 0000000..51d7d56 --- /dev/null +++ b/src/Utility/Components/Stopwatch/Stopwatch.razor @@ -0,0 +1,109 @@ +@using System.Timers +@implements IDisposable + +
+
+
+

Stopwatch

+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + @*
*@ + @*
*@ + @*

Inspired from

*@ + @*
*@ + @*
*@ + +
+ +@code { + [Parameter] + public string? Input { get; set; } + + [Parameter] + public EventCallback TimerOut { get; set; } + + private Timer timer = null!; + private int secondsToRun = 0; + + // protected override void OnInitialized() + // { + // // Input = "00:00"; + // timer = new System.Threading.Timer(async _ => // async void + // { + // Input = + // // we need StateHasChanged() because this is an async void handler + // // we need to Invoke it because we could be on the wrong Thread + // await InvokeAsync(StateHasChanged); + // }, null, 0, 1000); + // } + + void StartStop() + { + if (string.IsNullOrEmpty(Input)) return; + Start(10); + } + + void Reset() + { + Start(600); + } + + public void Start(int secondsToRun) + { + if (secondsToRun > 0) + { + Input = TimeSpan.FromSeconds(secondsToRun).ToString(@"mm\:ss"); + StateHasChanged(); + timer.Start(); + } + } + + public void Stop() + { + timer.Stop(); + } + + protected override void OnInitialized() + { + timer = new Timer(1000); + timer.Elapsed += OnTimedEvent; + timer.AutoReset = true; + } + + private async void OnTimedEvent(object? sender, ElapsedEventArgs e) + { + secondsToRun--; + + await InvokeAsync(() => + { + Input = TimeSpan.FromSeconds(secondsToRun).ToString(@"mm\:ss"); + StateHasChanged(); + }); + + if (secondsToRun <= 0) + { + timer.Stop(); + await TimerOut.InvokeAsync(); + } + } + + public void Dispose() + { + timer.Dispose(); + } + +} \ No newline at end of file diff --git a/src/Utility/Components/Stopwatch/Stopwatch.razor.css b/src/Utility/Components/Stopwatch/Stopwatch.razor.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Utility/Components/TimerControl/TimerControl.razor b/src/Utility/Components/TimerControl/TimerControl.razor new file mode 100644 index 0000000..62e288b --- /dev/null +++ b/src/Utility/Components/TimerControl/TimerControl.razor @@ -0,0 +1,109 @@ +@using System.Timers +@implements IDisposable + +
+
+
+

Timer

+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ + @*
*@ + @*
*@ + @*

Inspired from

*@ + @*
*@ + @*
*@ + +
+ +@code { + [Parameter] + public string? Input { get; set; } + + [Parameter] + public EventCallback TimerOut { get; set; } + + private Timer timer = null!; + private int secondsToRun = 0; + + // protected override void OnInitialized() + // { + // // Input = "00:00"; + // timer = new System.Threading.Timer(async _ => // async void + // { + // Input = + // // we need StateHasChanged() because this is an async void handler + // // we need to Invoke it because we could be on the wrong Thread + // await InvokeAsync(StateHasChanged); + // }, null, 0, 1000); + // } + + void StartStop() + { + if (string.IsNullOrEmpty(Input)) return; + + } + + void Reset() + { + + } + + public void Start(int secondsToRun) + { + if (secondsToRun > 0) + { + Input = TimeSpan.FromSeconds(secondsToRun).ToString(@"mm\:ss"); + StateHasChanged(); + timer.Start(); + } + } + + public void Stop() + { + timer.Stop(); + } + + protected override void OnInitialized() + { + timer = new Timer(1000); + timer.Elapsed += OnTimedEvent; + timer.AutoReset = true; + } + + private async void OnTimedEvent(object? sender, ElapsedEventArgs e) + { + secondsToRun--; + + await InvokeAsync(() => + { + Input = TimeSpan.FromSeconds(secondsToRun).ToString(@"mm\:ss"); + StateHasChanged(); + }); + + if (secondsToRun <= 0) + { + timer.Stop(); + await TimerOut.InvokeAsync(); + } + } + + public void Dispose() + { + timer.Dispose(); + } + +} \ No newline at end of file diff --git a/src/Utility/Components/TimerControl/TimerControl.razor.css b/src/Utility/Components/TimerControl/TimerControl.razor.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Utility/Pages/TimerStopwatch.razor b/src/Utility/Pages/TimerStopwatch.razor new file mode 100644 index 0000000..1345a91 --- /dev/null +++ b/src/Utility/Pages/TimerStopwatch.razor @@ -0,0 +1,12 @@ +@page "/timerstopwatch" + +@using Utility.Components.TimerControl +@using Utility.Components.Stopwatch + +️⏲️ Timer / ⏱️ Stopwatch + + + +
+ + diff --git a/src/Utility/Pages/TimerStopwatch.razor.css b/src/Utility/Pages/TimerStopwatch.razor.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Utility/Shared/NavMenu.razor b/src/Utility/Shared/NavMenu.razor index 75c0aa6..c6fa6c3 100644 --- a/src/Utility/Shared/NavMenu.razor +++ b/src/Utility/Shared/NavMenu.razor @@ -41,6 +41,11 @@ Markdown +