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
///
/// Close scan code callback method
///
[Parameter]
public EventCallback Close { get; set; }
///
/// Close button title
///
[Parameter]
public string CloseBtnTitle { get; set; } = "Close";
///
/// Decode All Formats, performance is poor, you can set options.formats to customize
/// specify the encoding formats. The default is false
///
[Parameter]
public bool DecodeAllFormats { get; set; }
///
/// Decode Once or Decode Continuously, default is Once
///
[Parameter]
public bool Decodeonce { get; set; } = true;
///
/// Device ID
///
[Parameter]
public string? DeviceID { get; set; }
///
///
public ElementReference Element { get; set; }
///
/// Error callback method
///
[Parameter]
public Func? OnError { get; set; }
///
/// ZXingOptions
///
[Parameter]
public ZXingOptions? Options { get; set; }
///
/// Decode only Pdf417 format
///
[Parameter]
public bool Pdf417Only { get; set; }
///
/// Reset button title
///
[Parameter]
public string ResetBtnTitle { get; set; } = "Reset";
///
/// Save the last used device ID to be called automatically next time
///
[Parameter]
public bool SaveDeviceID { get; set; } = true;
///
/// Scan button title
///
[Parameter]
public string ScanBtnTitle { get; set; } = "Scan";
///
/// Scan result callback method
///
[Parameter]
public EventCallback ScanResult { get; set; }
///
/// Select device button title
///
[Parameter]
public string SelectDeviceBtnTitle { get; set; } = "Select Device";
///
/// Use builtin Div
///
[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);
}
///
/// 选择摄像头回调方法
///
///
///
[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("import", "./_content/EgwCoreLib.Razor/BarcodeReader.razor.js");
#if false
module = await JS.InvokeAsync("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? 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(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 GetValue(string key, TValue? def)
{
try
{
var cValue = await JSRuntime.InvokeAsync("eval", $"localStorage.getItem('{key}');");
return cValue ?? def;
}
catch
{
var cValue = await JSRuntime.InvokeAsync("eval", $"localStorage.getItem('{key}');");
if (cValue == null)
return def;
var newValue = GetValueI(cValue);
return newValue ?? def;
}
}
public async Task RemoveValue(string key)
{
await JSRuntime.InvokeVoidAsync("eval", $"localStorage.removeItem('{key}')");
}
public async Task SetValue(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
}
}