Files
egwcorelib/EgwCoreLib.Razor/BarcodeReader.razor.cs
Samuele Locatelli 3aee8ec236 Update sorter
2025-06-30 19:43:01 +02:00

294 lines
8.4 KiB
C#

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using EgwCoreLib.Utils;
using ZXingBlazor.Components;
namespace EgwCoreLib.Razor
{
public partial class BarcodeReader : IAsyncDisposable
{
#region Public Properties
/// <summary>
/// Close scan code callback method
/// </summary>
[Parameter]
public EventCallback Close { get; set; }
/// <summary>
/// Close button title
/// </summary>
[Parameter]
public string CloseBtnTitle { get; set; } = "Close";
/// <summary>
/// Decode All Formats, performance is poor, you can set options.formats to customize
/// specify the encoding formats. The default is false
/// </summary>
[Parameter]
public bool DecodeAllFormats { get; set; }
/// <summary>
/// Decode Once or Decode Continuously, default is Once
/// </summary>
[Parameter]
public bool Decodeonce { get; set; } = true;
/// <summary>
/// Device ID
/// </summary>
[Parameter]
public string? DeviceID { get; set; }
/// <summary>
/// </summary>
public ElementReference Element { get; set; }
/// <summary>
/// Error callback method
/// </summary>
[Parameter]
public Func<string, Task>? OnError { get; set; }
/// <summary>
/// ZXingOptions
/// </summary>
[Parameter]
public ZXingOptions? Options { get; set; }
/// <summary>
/// Decode only Pdf417 format
/// </summary>
[Parameter]
public bool Pdf417Only { get; set; }
/// <summary>
/// Reset button title
/// </summary>
[Parameter]
public string ResetBtnTitle { get; set; } = "Reset";
/// <summary>
/// Save the last used device ID to be called automatically next time
/// </summary>
[Parameter]
public bool SaveDeviceID { get; set; } = true;
/// <summary>
/// Scan button title
/// </summary>
[Parameter]
public string ScanBtnTitle { get; set; } = "Scan";
/// <summary>
/// Scan result callback method
/// </summary>
[Parameter]
public EventCallback<string> ScanResult { get; set; }
/// <summary>
/// Select device button title
/// </summary>
[Parameter]
public string SelectDeviceBtnTitle { get; set; } = "Select Device";
/// <summary>
/// Use builtin Div
/// </summary>
[Parameter] public bool UseBuiltinDiv { get; set; } = true;
#endregion Public Properties
#region Public Methods
[JSInvokable]
public async Task CloseScan() => await Close.InvokeAsync();
async ValueTask IAsyncDisposable.DisposeAsync()
{
await module!.InvokeVoidAsync("destroy", Element.Id);
Instance?.Dispose();
if (module is not null)
{
await module.DisposeAsync();
}
}
[JSInvokable]
public async Task GetError(string err)
{
if (OnError != null) await OnError.Invoke(err);
}
[JSInvokable]
public async Task GetResult(string val) => await ScanResult.InvokeAsync(val);
public async Task Reload()
{
await module!.InvokeVoidAsync("reload", Element.Id);
}
/// <summary>
/// 选择摄像头回调方法
/// </summary>
/// <param name="base64encodedstring"></param>
/// <returns></returns>
[JSInvokable]
public async Task SelectDeviceID(string deviceID, string deviceName)
{
try
{
if (SaveDeviceID)
{
await Storage.SetValue("CamsDeviceID", deviceID);
await Storage.SetValue("CamsDeviceName", deviceName);
}
}
catch
{
}
}
public async Task Start()
{
await module!.InvokeVoidAsync("start", Element.Id);
}
public async Task Stop()
{
await module!.InvokeVoidAsync("stop", Element.Id);
}
#endregion Public Methods
#region Protected Methods
// To prevent making JavaScript interop calls during prerendering
protected override async Task OnAfterRenderAsync(bool firstRender)
{
try
{
if (!firstRender) return;
Storage = new StorageService(JS);
module = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/EgwCoreLib.Razor/BarcodeReader.razor.js");
#if false
module = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/EgwCoreLib.Razor/BarcodeReader.razor.js" + "?v=" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
#endif
Instance = DotNetObjectReference.Create(this);
if (Options == null)
{
Options = new ZXingOptions()
{
Pdf417 = Pdf417Only,
Decodeonce = Decodeonce,
DecodeAllFormats = DecodeAllFormats,
//TRY_HARDER = true
};
}
try
{
if (SaveDeviceID)
{
DeviceID = await Storage.GetValue("CamsDeviceID", DeviceID);
}
}
catch (Exception)
{
}
await module.InvokeVoidAsync("init", Instance, Element, Element.Id, Options, DeviceID);
}
catch (Exception e)
{
if (OnError != null) await OnError.Invoke(e.Message);
}
}
#endregion Protected Methods
#region Private Fields
private IJSObjectReference? module;
#endregion Private Fields
#region Private Properties
private DotNetObjectReference<BarcodeReader>? Instance { get; set; }
[Inject]
[NotNull]
private IJSRuntime? JS { get; set; }
[NotNull]
private StorageService? Storage { get; set; }
#endregion Private Properties
#region Private Classes
private class StorageService
{
#region Public Constructors
public StorageService(IJSRuntime jsRuntime)
{
JSRuntime = jsRuntime;
}
#endregion Public Constructors
#region Public Methods
public static T? GetValueI<T>(string value)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
return (T?)converter.ConvertFrom(value);
}
return default;
//return (T)Convert.ChangeType(value, typeof(T));
}
public async Task<TValue?> GetValue<TValue>(string key, TValue? def)
{
try
{
var cValue = await JSRuntime.InvokeAsync<TValue>("eval", $"localStorage.getItem('{key}');");
return cValue ?? def;
}
catch
{
var cValue = await JSRuntime.InvokeAsync<string>("eval", $"localStorage.getItem('{key}');");
if (cValue == null)
return def;
var newValue = GetValueI<TValue>(cValue);
return newValue ?? def;
}
}
public async Task RemoveValue(string key)
{
await JSRuntime.InvokeVoidAsync("eval", $"localStorage.removeItem('{key}')");
}
public async Task SetValue<TValue>(string key, TValue value)
{
await JSRuntime.InvokeVoidAsync("eval", $"localStorage.setItem('{key}', '{value}')");
}
#endregion Public Methods
#region Private Fields
private readonly IJSRuntime JSRuntime;
#endregion Private Fields
}
#endregion Private Classes
}
}