Browse Source

Added equipment barcode scanner for android

Kenric Nugteren 1 week ago
parent
commit
c06b998a16

+ 3 - 0
PRS.Avalonia/PRS.Avalonia.Android/MainActivity.cs

@@ -5,6 +5,8 @@ using Avalonia;
 using Avalonia.Android;
 using InABox.Avalonia.Platform;
 using InABox.Avalonia.Platform.Android;
+using InABox.Avalonia.Platform.Android.Barcodes;
+using InABox.Avalonia.Platform.Barcodes;
 
 namespace PRS.Avalonia.Android;
 
@@ -30,6 +32,7 @@ public class MainActivity : AvaloniaMainActivity<App>
         PlatformTools.Register<IImageTools, Android_ImageTools>();
         PlatformTools.Register<IPdfRenderer, Android_PdfRenderer>();
         PlatformTools.Register<IBluetooth, Android_Bluetooth>();
+        PlatformTools.Register<ICameraViewControl, Android_CameraViewControl>();
         
         
         

+ 5 - 6
PRS.Avalonia/PRS.Avalonia.Android/Properties/AndroidManifest.xml

@@ -1,14 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
-	
 	<uses-permission android:name="android.permission.INTERNET" />
-	
-	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 	<uses-permission android:name="android.permission.BLUETOOTH" />
 	<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
 	<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
 	<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
-	
+	<uses-permission android:name="android.permission.CAMERA" />
+	<uses-permission android:name="android.permission.VIBRATE" />
 	<application android:label="PRS.Avalonia" android:icon="@drawable/Icon" />
-</manifest>
+</manifest>

+ 15 - 0
PRS.Avalonia/PRS.Avalonia/Components/Scanner/ScannerView.axaml

@@ -0,0 +1,15 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:components="using:PRS.Avalonia.Components"
+			 xmlns:barcodes="using:InABox.Avalonia.Platform.Barcodes"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+             x:Class="PRS.Avalonia.Components.ScannerView"
+             x:DataType="components:ScannerViewModel">
+	<Border ClipToBounds="True">
+		<barcodes:CameraView Name="CameraView"
+							 CameraEnabled="{Binding CameraEnabled}"
+							 OnDetectionFinishedCommand="{Binding DetectionFinishedCommand}"/>
+	</Border>
+</UserControl>

+ 25 - 0
PRS.Avalonia/PRS.Avalonia/Components/Scanner/ScannerView.axaml.cs

@@ -0,0 +1,25 @@
+using Avalonia.Controls;
+using ReactiveUI;
+using System;
+
+namespace PRS.Avalonia.Components;
+
+public partial class ScannerView : UserControl
+{
+    public ScannerView()
+    {
+        InitializeComponent();
+
+        // Scanner = (Host.Content as CameraView)!;
+    }
+
+    // protected override void OnDataContextChanged(EventArgs e)
+    // {
+    //     base.OnDataContextChanged(e);
+
+    //     var model = DataContext as EquipmentScannerViewModel;
+    //     if (model is null) return;
+
+    //     model.WhenAnyValue(x => x.CameraEnabled).Subscribe(x => Scanner.CameraEnabled = x);
+    // }
+}

+ 59 - 0
PRS.Avalonia/PRS.Avalonia/Components/Scanner/ScannerViewModel.cs

@@ -0,0 +1,59 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using InABox.Avalonia.Platform.Barcodes;
+using Microsoft.Maui.Devices;
+using PRS.Avalonia.Modules;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace PRS.Avalonia.Components;
+
+public partial class ScannerViewModel : ModuleViewModel
+{
+    public override string Title => "Equipment Scanner";
+
+    [ObservableProperty]
+    private bool _cameraEnabled;
+
+    [ObservableProperty]
+    private bool _processing;
+
+    [ObservableProperty]
+    private Func<IReadOnlySet<BarcodeResult>, Task<bool>>? _itemScanned;
+
+    public ScannerViewModel()
+    {
+    }
+
+    protected override Task OnActivated()
+    {
+        CameraEnabled = true;
+        return base.OnActivated();
+    }
+
+    protected override Task OnDeactivated()
+    {
+        CameraEnabled = false;
+        return base.OnDeactivated();
+    }
+
+    [RelayCommand]
+    private async Task DetectionFinished(IReadOnlySet<BarcodeResult> result)
+    {
+        if(result.Count > 0)
+        {
+            if (Processing || !CameraEnabled) return;
+
+            Processing = true;
+            if(ItemScanned != null)
+            {
+                if(await ItemScanned.Invoke(result))
+                {
+                    CameraEnabled = false;
+                }
+            }
+            Processing = false;
+        }
+    }
+}

+ 65 - 4
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentModuleViewModel.cs

@@ -1,6 +1,15 @@
+using Comal.Classes;
 using CommunityToolkit.Mvvm.ComponentModel;
+using InABox.Avalonia;
 using InABox.Avalonia.Components;
+using InABox.Avalonia.Dialogs;
+using InABox.Core;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Maui.Devices;
 using PRS.Avalonia.Components;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
 
 namespace PRS.Avalonia.Modules;
 
@@ -11,11 +20,11 @@ public partial class EquipmentModuleViewModel : ModuleViewModel
     public EquipmentModuleViewModel()
     {
         Modules = new AvaloniaModuleCollection();
-        Modules.Add<EquipmentScannerViewModel>(
-            "Equipment Scanner", 
-            "Identify Equipment from a barcode", 
+        Modules.Add(
+            "Equipment Scanner",
+            "Identify Equipment from a barcode",
             Images.barcode,
-            isVisible: false);
+            Scanner_Tapped);
         
         Modules.Add<EquipmentListViewModel>(
             "Equipment List", 
@@ -34,4 +43,56 @@ public partial class EquipmentModuleViewModel : ModuleViewModel
     }
 
     public override string Title => "Equipment";
+
+    private void Scanner_Tapped()
+    {
+        Navigation.Navigate<ScannerViewModel>(model =>
+        {
+            model.ItemScanned = async (results) =>
+            {
+                Guid? equipmentID = null;
+                foreach(var barCode in results)
+                {
+                    if (Guid.TryParse(barCode.RawValue, out var eID))
+                    {
+                        equipmentID = eID;
+                        break;
+                    }
+                }
+                if(equipmentID is null)
+                {
+                    Vibration.Vibrate();
+                    await Task.Delay(200);
+                    Vibration.Vibrate();
+                    await Task.Delay(1000);
+                    //await MessageDialog.ShowMessage("Invalid Code");
+                    return false;
+                }
+                else
+                {
+                    Vibration.Vibrate();
+                    var model = new EquipmentModel(
+                        DataAccess,
+                        () => new Filter<Equipment>(x => x.ID).IsEqualTo(equipmentID),
+                        () => DefaultCacheFileName<EquipmentShell>());
+                    await model.RefreshAsync(true);
+
+                    var equipment = model.FirstOrDefault();
+                    if(equipment is null)
+                    {
+                        // await MessageDialog.ShowMessage("Cannot load equipment!");
+                        return false;
+                    }
+                    else
+                    {
+                        Navigation.Navigate<EquipmentDetailsViewModel>(model =>
+                        {
+                            model.Shell = equipment;
+                        });
+                        return true;
+                    }
+                }
+            };
+        });
+    }
 }

+ 0 - 10
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentScanner/EquipmentScannerView.axaml

@@ -1,10 +0,0 @@
-<UserControl xmlns="https://github.com/avaloniaui"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-             xmlns:modules="clr-namespace:PRS.Avalonia.Modules"
-             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
-             x:Class="PRS.Avalonia.Modules.EquipmentScannerView"
-             x:DataType="modules:EquipmentScannerViewModel">
-    Welcome to Avalonia!
-</UserControl>

+ 0 - 11
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentScanner/EquipmentScannerView.axaml.cs

@@ -1,11 +0,0 @@
-using Avalonia.Controls;
-
-namespace PRS.Avalonia.Modules;
-
-public partial class EquipmentScannerView : UserControl
-{
-    public EquipmentScannerView()
-    {
-        InitializeComponent();
-    }
-}

+ 0 - 6
PRS.Avalonia/PRS.Avalonia/Modules/EquipmentModule/EquipmentScanner/EquipmentScannerViewModel.cs

@@ -1,6 +0,0 @@
-namespace PRS.Avalonia.Modules;
-
-public class EquipmentScannerViewModel : ModuleViewModel
-{
-    public override string Title => "Equipment Scanner";
-}

+ 6 - 0
PRS.Avalonia/PRS.Avalonia/PRS.Avalonia.csproj

@@ -333,12 +333,18 @@
     </ItemGroup>
 
     <ItemGroup>
+        <Compile Update="Components\DocumentList\DocumentPageView.axaml.cs">
+          <DependentUpon>DocumentPageView.axaml</DependentUpon>
+        </Compile>
         <Compile Update="Components\FormsEditor\DigitalFormsHostView.axaml.cs">
           <DependentUpon>DigitalFormsHostView.axaml</DependentUpon>
         </Compile>
         <Compile Update="Components\FormsList\FormsList.axaml.cs">
           <DependentUpon>FormsList.axaml</DependentUpon>
         </Compile>
+        <Compile Update="Components\Scanner\ScannerView.axaml.cs">
+          <DependentUpon>ScannerView.axaml</DependentUpon>
+        </Compile>
         <Compile Update="Components\SelectionView\SelectionView.axaml.cs">
           <DependentUpon>SelectionView.axaml</DependentUpon>
         </Compile>

+ 1 - 1
PRS.Avalonia/PRS.Avalonia/Repositories/EquipmentDocumentShell/EquipmentDocumentModel.cs

@@ -7,7 +7,7 @@ namespace PRS.Avalonia;
 
 public class EquipmentDocumentModel : CoreRepository<EquipmentDocumentModel, EquipmentDocumentShell, EquipmentDocument>
 {
-    public EquipmentDocumentModel(IModelHost host, Func<Filter<EquipmentDocument>> filter) : base(host, filter)
+    public EquipmentDocumentModel(IModelHost host, Func<Filter<EquipmentDocument>> filter, Func<string>? filename = null) : base(host, filter, filename)
     {
     }
 }