Scan ean code on iOS app
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0-ios</TargetFramework>
|
<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 -->
|
<!-- 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> -->
|
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
||||||
|
|
||||||
@@ -21,10 +23,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<!-- Display name -->
|
<!-- Display name -->
|
||||||
<ApplicationTitle>Bimix.UI.Mobile</ApplicationTitle>
|
<ApplicationTitle>Bimix</ApplicationTitle>
|
||||||
|
|
||||||
<!-- App Identifier -->
|
<!-- App Identifier -->
|
||||||
<ApplicationId>com.companyname.bimix.ui.mobile</ApplicationId>
|
<ApplicationId>cloud.bimit.bimix</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
||||||
@@ -38,6 +40,14 @@
|
|||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
|
||||||
</PropertyGroup>
|
</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>
|
<ItemGroup>
|
||||||
<!-- App Icon -->
|
<!-- App Icon -->
|
||||||
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4"/>
|
<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.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1"/>
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1"/>
|
||||||
<PackageReference Include="MudBlazor" Version="8.8.0"/>
|
<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>
|
||||||
|
|
||||||
<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 Microsoft.Extensions.Logging;
|
||||||
using MudBlazor.Services;
|
using MudBlazor.Services;
|
||||||
|
using ZXing.Net.Maui.Controls;
|
||||||
|
|
||||||
namespace Bimix.UI.Mobile;
|
namespace Bimix.UI.Mobile;
|
||||||
|
|
||||||
@@ -11,12 +14,21 @@ public static class MauiProgram
|
|||||||
var builder = MauiApp.CreateBuilder();
|
var builder = MauiApp.CreateBuilder();
|
||||||
builder
|
builder
|
||||||
.UseMauiApp<App>()
|
.UseMauiApp<App>()
|
||||||
|
.UseBarcodeReader()
|
||||||
.ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); });
|
.ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); });
|
||||||
|
|
||||||
builder.Services.AddMauiBlazorWebView();
|
builder.Services.AddMauiBlazorWebView();
|
||||||
|
|
||||||
builder.Services.AddMudServices();
|
builder.Services.AddMudServices();
|
||||||
|
|
||||||
|
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton<IScannerService, ScannerService>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton<IScannerService, NoOpScannerService>();
|
||||||
|
}
|
||||||
|
|
||||||
var baseUrl = GetApiBaseUrl();
|
var baseUrl = GetApiBaseUrl();
|
||||||
builder.Services.AddSharedServices(baseUrl);
|
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>
|
||||||
|
|
||||||
<MudItem xs="12" sm="6" md="4">
|
<MudItem xs="12" sm="6" md="4">
|
||||||
<MudTextField @bind-Value="filterRequest.Ean"
|
<div style="display: flex; gap: 8px; align-items: flex-end;">
|
||||||
Label="EAN"
|
<div style="flex: 1;">
|
||||||
Immediate="true"
|
<MudTextField @bind-Value="filterRequest.Ean"
|
||||||
DebounceInterval="500"
|
Label="EAN"
|
||||||
OnDebounceIntervalElapsed="SearchProducts"
|
Immediate="true"
|
||||||
Clearable="true">
|
DebounceInterval="500"
|
||||||
</MudTextField>
|
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>
|
||||||
|
|
||||||
<MudItem xs="12" sm="6" md="4">
|
<MudItem xs="12" sm="6" md="4">
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
using Bimix.Application.DTOModels;
|
using Bimix.Application.DTOModels;
|
||||||
using Bimix.Application.DTOModels.Common;
|
using Bimix.Application.DTOModels.Common;
|
||||||
using Bimix.Domain.Entities;
|
using Bimix.UI.Shared.Interfaces;
|
||||||
using Bimix.UI.Shared.Services;
|
using Bimix.UI.Shared.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using MudBlazor;
|
||||||
using Microsoft.JSInterop;
|
|
||||||
|
|
||||||
namespace Bimix.UI.Shared.Components;
|
namespace Bimix.UI.Shared.Components;
|
||||||
|
|
||||||
public partial class ProductListComponent : ComponentBase
|
public partial class ProductListComponent : ComponentBase
|
||||||
{
|
{
|
||||||
[Inject] private ProductService ProductService { get; set; } = default!;
|
[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 PagedResult<ProductDto> products = new();
|
||||||
private ProductFilterRequest filterRequest = new();
|
private ProductFilterRequest filterRequest = new();
|
||||||
@@ -21,11 +24,6 @@ public partial class ProductListComponent : ComponentBase
|
|||||||
await LoadProducts();
|
await LoadProducts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartBarcodeScanner()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadProducts()
|
private async Task LoadProducts()
|
||||||
{
|
{
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -74,4 +72,34 @@ public partial class ProductListComponent : ComponentBase
|
|||||||
Console.WriteLine($"Usuń produkt: {productId}");
|
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;
|
||||||
using Bimix.UI.Shared.Extensions;
|
using Bimix.UI.Shared.Extensions;
|
||||||
|
using Bimix.UI.Shared.Interfaces;
|
||||||
using Bimix.UI.Web.Components;
|
using Bimix.UI.Web.Components;
|
||||||
using MudBlazor.Services;
|
using MudBlazor.Services;
|
||||||
|
|
||||||
@@ -11,6 +12,8 @@ builder.Services.AddMudServices();
|
|||||||
|
|
||||||
builder.Services.AddSharedServices("http://localhost:7142");
|
builder.Services.AddSharedServices("http://localhost:7142");
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<IScannerService, NoOpScannerService>();
|
||||||
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user