Scan ean code on iOS app
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-ios</TargetFramework>
|
||||
<GenerateXcodeProject>true</GenerateXcodeProject>
|
||||
|
||||
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
|
||||
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
||||
|
||||
@@ -21,10 +23,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<!-- Display name -->
|
||||
<ApplicationTitle>Bimix.UI.Mobile</ApplicationTitle>
|
||||
<ApplicationTitle>Bimix</ApplicationTitle>
|
||||
|
||||
<!-- App Identifier -->
|
||||
<ApplicationId>com.companyname.bimix.ui.mobile</ApplicationId>
|
||||
<ApplicationId>cloud.bimit.bimix</ApplicationId>
|
||||
|
||||
<!-- Versions -->
|
||||
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
||||
@@ -38,6 +40,14 @@
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Platform)' == 'iPhone'">
|
||||
<ApplicationId>cloud.bimit.bimix</ApplicationId>
|
||||
<CodesignKey>Apple Development: Michal Zielinski (2F35ZHMBTB)</CodesignKey>
|
||||
<CodesignProvision>bimix-local</CodesignProvision>
|
||||
<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<!-- App Icon -->
|
||||
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4"/>
|
||||
@@ -66,7 +76,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1"/>
|
||||
<PackageReference Include="MudBlazor" Version="8.8.0"/>
|
||||
|
||||
<PackageReference Include="ZXing.Net.MAUI" Version="0.4.0" />
|
||||
<PackageReference Include="ZXing.Net.MAUI.Controls" Version="0.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Bimix.UI.Shared.Extensions;
|
||||
using Bimix.UI.Mobile.Services;
|
||||
using Bimix.UI.Shared.Extensions;
|
||||
using Bimix.UI.Shared.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MudBlazor.Services;
|
||||
using ZXing.Net.Maui.Controls;
|
||||
|
||||
namespace Bimix.UI.Mobile;
|
||||
|
||||
@@ -11,12 +14,21 @@ public static class MauiProgram
|
||||
var builder = MauiApp.CreateBuilder();
|
||||
builder
|
||||
.UseMauiApp<App>()
|
||||
.UseBarcodeReader()
|
||||
.ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); });
|
||||
|
||||
builder.Services.AddMauiBlazorWebView();
|
||||
|
||||
builder.Services.AddMudServices();
|
||||
|
||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||
{
|
||||
builder.Services.AddSingleton<IScannerService, ScannerService>();
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddSingleton<IScannerService, NoOpScannerService>();
|
||||
}
|
||||
|
||||
var baseUrl = GetApiBaseUrl();
|
||||
builder.Services.AddSharedServices(baseUrl);
|
||||
|
||||
|
||||
140
Bimix.UI.Mobile/Services/ScannerService.cs
Normal file
140
Bimix.UI.Mobile/Services/ScannerService.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using Bimix.UI.Shared.Interfaces;
|
||||
using ZXing.Net.Maui;
|
||||
using ZXing.Net.Maui.Controls;
|
||||
|
||||
namespace Bimix.UI.Mobile.Services;
|
||||
|
||||
public class ScannerService : IScannerService
|
||||
{
|
||||
public bool IsAvailable => true;
|
||||
|
||||
public async Task<string?> ScanBarcodeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsAvailable)
|
||||
return null;
|
||||
|
||||
var hasPermission = await RequestCameraPermissionsAsync();
|
||||
if (!hasPermission)
|
||||
return null;
|
||||
|
||||
var tcs = new TaskCompletionSource<string?>();
|
||||
|
||||
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||
{
|
||||
var scanner = new CameraBarcodeReaderView
|
||||
{
|
||||
Options = new BarcodeReaderOptions
|
||||
{
|
||||
Formats = BarcodeFormats.OneDimensional | BarcodeFormats.TwoDimensional,
|
||||
AutoRotate = true,
|
||||
Multiple = false
|
||||
},
|
||||
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||
VerticalOptions = LayoutOptions.FillAndExpand,
|
||||
BackgroundColor = Colors.Black
|
||||
};
|
||||
|
||||
scanner.BarcodesDetected += async (sender, e) =>
|
||||
{
|
||||
if (e.Results?.Any() == true)
|
||||
{
|
||||
var barcode = e.Results.First();
|
||||
|
||||
// Wykonaj operacje UI na głównym wątku
|
||||
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Microsoft.Maui.Controls.Application.Current?.MainPage?.Navigation.PopModalAsync()!;
|
||||
tcs.TrySetResult(barcode.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error closing modal: {ex.Message}");
|
||||
tcs.TrySetException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var cancelButton = new Button
|
||||
{
|
||||
Text = "Anuluj",
|
||||
BackgroundColor = Colors.Red,
|
||||
TextColor = Colors.White,
|
||||
Margin = new Thickness(20),
|
||||
HorizontalOptions = LayoutOptions.Center
|
||||
};
|
||||
|
||||
cancelButton.Clicked += async (sender, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Microsoft.Maui.Controls.Application.Current?.MainPage?.Navigation.PopModalAsync()!;
|
||||
tcs.TrySetResult(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error closing modal: {ex.Message}");
|
||||
tcs.TrySetException(ex);
|
||||
}
|
||||
};
|
||||
|
||||
var stackLayout = new StackLayout
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label
|
||||
{
|
||||
Text = "Skieruj kamerę na kod kreskowy",
|
||||
HorizontalOptions = LayoutOptions.Center,
|
||||
VerticalOptions = LayoutOptions.Start,
|
||||
Margin = new Thickness(20),
|
||||
FontSize = 18,
|
||||
TextColor = Colors.White
|
||||
},
|
||||
scanner,
|
||||
cancelButton
|
||||
},
|
||||
BackgroundColor = Colors.Black,
|
||||
Spacing = 0
|
||||
};
|
||||
|
||||
var scannerPage = new ContentPage
|
||||
{
|
||||
Title = "Skanuj kod",
|
||||
Content = stackLayout,
|
||||
BackgroundColor = Colors.Black
|
||||
};
|
||||
|
||||
await Microsoft.Maui.Controls.Application.Current?.MainPage?.Navigation.PushModalAsync(scannerPage)!;
|
||||
});
|
||||
|
||||
var result = await tcs.Task;
|
||||
System.Diagnostics.Debug.WriteLine($"Scanner returned: {result}");
|
||||
return result;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Scanner error: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> RequestCameraPermissionsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var status = await Permissions.RequestAsync<Permissions.Camera>();
|
||||
return status == PermissionStatus.Granted;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Permission error: {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,13 +36,26 @@
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudTextField @bind-Value="filterRequest.Ean"
|
||||
Label="EAN"
|
||||
Immediate="true"
|
||||
DebounceInterval="500"
|
||||
OnDebounceIntervalElapsed="SearchProducts"
|
||||
Clearable="true">
|
||||
</MudTextField>
|
||||
<div style="display: flex; gap: 8px; align-items: flex-end;">
|
||||
<div style="flex: 1;">
|
||||
<MudTextField @bind-Value="filterRequest.Ean"
|
||||
Label="EAN"
|
||||
Immediate="true"
|
||||
DebounceInterval="500"
|
||||
OnDebounceIntervalElapsed="SearchProducts"
|
||||
Clearable="true"/>
|
||||
</div>
|
||||
@if (ScannerService.IsAvailable)
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Filled.CameraAlt"
|
||||
Color="Color.Primary"
|
||||
OnClick="OnScannerClick"
|
||||
Variant="Variant.Filled"
|
||||
Size="Size.Medium"
|
||||
Title="Skanuj kod EAN"/>
|
||||
}
|
||||
</div>
|
||||
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
using Bimix.Application.DTOModels;
|
||||
using Bimix.Application.DTOModels.Common;
|
||||
using Bimix.Domain.Entities;
|
||||
using Bimix.UI.Shared.Interfaces;
|
||||
using Bimix.UI.Shared.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using MudBlazor;
|
||||
|
||||
|
||||
namespace Bimix.UI.Shared.Components;
|
||||
|
||||
public partial class ProductListComponent : ComponentBase
|
||||
{
|
||||
[Inject] private ProductService ProductService { get; set; } = default!;
|
||||
[Inject] private IScannerService ScannerService { get; set; } = default!;
|
||||
[Inject] private ISnackbar Snackbar { get; set; } = default!;
|
||||
|
||||
|
||||
private PagedResult<ProductDto> products = new();
|
||||
private ProductFilterRequest filterRequest = new();
|
||||
@@ -21,11 +24,6 @@ public partial class ProductListComponent : ComponentBase
|
||||
await LoadProducts();
|
||||
}
|
||||
|
||||
private async Task StartBarcodeScanner()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async Task LoadProducts()
|
||||
{
|
||||
isLoading = true;
|
||||
@@ -74,4 +72,34 @@ public partial class ProductListComponent : ComponentBase
|
||||
Console.WriteLine($"Usuń produkt: {productId}");
|
||||
}
|
||||
|
||||
private string GetScannerIcon()
|
||||
{
|
||||
return ScannerService.IsAvailable ? Icons.Material.Filled.CameraAlt : "";
|
||||
}
|
||||
|
||||
private async Task OnScannerClick()
|
||||
{
|
||||
if (!ScannerService.IsAvailable)
|
||||
{
|
||||
Snackbar.Add("Skaner nie jest dostępny na tej platformie", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var scannedCode = await ScannerService.ScanBarcodeAsync();
|
||||
if (!string.IsNullOrEmpty(scannedCode))
|
||||
{
|
||||
filterRequest.Ean = scannedCode;
|
||||
await SearchProducts();
|
||||
Snackbar.Add($"Zeskanowano kod: {scannedCode}", Severity.Success);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Scanner error: {ex.Message}");
|
||||
Snackbar.Add("Błąd podczas skanowania", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
9
Bimix.UI.Shared/Interfaces/IScannerService.cs
Normal file
9
Bimix.UI.Shared/Interfaces/IScannerService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bimix.UI.Shared.Interfaces;
|
||||
|
||||
public interface IScannerService
|
||||
{
|
||||
bool IsAvailable { get; }
|
||||
Task<bool> RequestCameraPermissionsAsync();
|
||||
Task<string?> ScanBarcodeAsync();
|
||||
|
||||
}
|
||||
16
Bimix.UI.Shared/Services/NoOpScannerService.cs
Normal file
16
Bimix.UI.Shared/Services/NoOpScannerService.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Bimix.UI.Shared.Interfaces;
|
||||
|
||||
public class NoOpScannerService : IScannerService
|
||||
{
|
||||
public bool IsAvailable => false;
|
||||
public Task<string?> ScanBarcodeAsync()
|
||||
{
|
||||
return Task.FromResult<string?>(null);
|
||||
}
|
||||
public Task<bool> RequestCameraPermissionsAsync()
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bimix.UI.Shared;
|
||||
using Bimix.UI.Shared.Extensions;
|
||||
using Bimix.UI.Shared.Interfaces;
|
||||
using Bimix.UI.Web.Components;
|
||||
using MudBlazor.Services;
|
||||
|
||||
@@ -11,6 +12,8 @@ builder.Services.AddMudServices();
|
||||
|
||||
builder.Services.AddSharedServices("http://localhost:7142");
|
||||
|
||||
builder.Services.AddSingleton<IScannerService, NoOpScannerService>();
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user