Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>9.5.11-beta05</Version>
<Version>9.5.11-beta06</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
68 changes: 36 additions & 32 deletions src/BootstrapBlazor/Components/Speech/SpeechWave.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,10 @@ public partial class SpeechWave : IDisposable
public Func<Task>? OnTimeout { get; set; }

/// <summary>
/// 获得/设置 总时长 默认 60000 毫秒
/// 获得/设置 总时长 默认 60 000 毫秒
/// </summary>
[Parameter]
public int TotalTime { get; set; } = 60000;

private TimeSpan UsedTimeSpan { get; set; }

private CancellationTokenSource? Token { get; set; }
public int TotalTime { get; set; } = 60 * 1000;

private string? ClassString => CssBuilder.Default("speech-wave")
.AddClass("invisible", !Show)
Expand All @@ -49,71 +45,79 @@ public partial class SpeechWave : IDisposable

private string? TotalTimeSpanString => $"{TimeSpan.FromMilliseconds(TotalTime):mm\\:ss}";

private string? UsedTimeSpanString => $"{UsedTimeSpan:mm\\:ss}";
private string? UsedTimeSpanString => $"{_usedTimeSpan:mm\\:ss}";

private bool _run;
private TimeSpan _usedTimeSpan;
private CancellationTokenSource? _token;

/// <summary>
/// OnParametersSet 方法
/// <inheritdoc/>
/// </summary>
protected override void OnParametersSet()
/// <returns></returns>
protected override async Task OnParametersSetAsync()
{
base.OnParametersSet();

await base.OnParametersSetAsync();

if (Show)
{
Run();
await Run();
}
else
{
Cancel();
Stop();
}
}

private bool IsRun { get; set; }
private bool IsShow => _token is { IsCancellationRequested: false };

private void Run() => Task.Run(async () =>
private async Task Run()
{
if (!IsRun)
if (!_run)
{
IsRun = true;
UsedTimeSpan = TimeSpan.Zero;
Token ??= new CancellationTokenSource();
_run = true;
_usedTimeSpan = TimeSpan.Zero;
_token ??= new CancellationTokenSource();
while (IsShow)
{
try
{
await Task.Delay(1000, Token.Token);
UsedTimeSpan = UsedTimeSpan.Add(TimeSpan.FromSeconds(1));
if (UsedTimeSpan.TotalMilliseconds >= TotalTime)
await Task.Delay(1000, _token.Token);
_usedTimeSpan = _usedTimeSpan.Add(TimeSpan.FromSeconds(1));
if (_usedTimeSpan.TotalMilliseconds >= TotalTime)
{
Show = false;
if (OnTimeout != null)
{
await OnTimeout();
}
}
await InvokeAsync(StateHasChanged);

if (ShowUsedTime || Show == false)
{
StateHasChanged();
}
}
catch (TaskCanceledException)
{
break;
}
}
IsRun = false;
_run = false;
}
});
}

private void Cancel()
private void Stop()
{
if (Token != null)
if (_token != null)
{
Token.Cancel();
Token.Dispose();
Token = null;
_token.Cancel();
_token.Dispose();
_token = null;
}
}

private bool IsShow => Token != null && !Token.IsCancellationRequested;

/// <summary>
/// Dispose 方法
/// </summary>
Expand All @@ -122,7 +126,7 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Cancel();
Stop();
}
}

Expand Down
34 changes: 21 additions & 13 deletions test/UnitTest/Components/RecognizerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

using System.Runtime.CompilerServices;

namespace UnitTest.Components;

public class RecognizerTest : SpeechTestBase
Expand Down Expand Up @@ -79,29 +81,35 @@ public async Task SpeechWave_OnTimeout_Test()
cut.SetParametersAndRender(pb =>
{
pb.Add(a => a.Show, true);
pb.Add(a => a.ShowUsedTime, false);
});
await Task.Delay(500);
await Task.Delay(1200);

cut.SetParametersAndRender(pb =>
{
pb.Add(a => a.Show, false);
});
}

[Fact]
public void IsCancelled_Ok()
public void Token_Ok()
{
var cut = Context.RenderComponent<SpeechWave>();
var pi = cut.Instance.GetType().GetProperty("IsShow", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var tokenPi = cut.Instance.GetType().GetProperty("Token", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var cut = Context.RenderComponent<SpeechWave>(pb =>
{
pb.Add(a => a.Show, true);
});
var token = GetToken(cut.Instance);
var shown = GetShow(cut.Instance);
Assert.True(shown);

Assert.False((bool?)pi?.GetValue(cut.Instance));
GetToken(cut.Instance) = null;
shown = GetShow(cut.Instance);
Assert.False(shown);
}

var token = new CancellationTokenSource();
tokenPi?.SetValue(cut.Instance, token);
Assert.True((bool?)pi?.GetValue(cut.Instance));
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_token")]
static extern ref CancellationTokenSource? GetToken(SpeechWave @this);

token.Cancel();
Assert.False((bool?)pi?.GetValue(cut.Instance));
Context.DisposeComponents();
}
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_IsShow")]
static extern bool GetShow(SpeechWave @this);
}
Loading