2using CommunityToolkit.Maui.Layouts;
3using CommunityToolkit.Mvvm.Input;
4using CommunityToolkit.Mvvm.Messaging;
5using Microsoft.Maui.Controls.PlatformConfiguration;
6using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
10using Android.Graphics;
11using AndroidX.Camera.Core;
12using AndroidX.Camera.Core.Impl;
14using System.Reflection;
15using ZXing.Net.Maui.Controls;
16using ZXing.Net.Maui.Readers;
31 this.InitializeComponent();
33 ScanQrCodeNavigationArgs? args =
ServiceRef.
UiService.PopLatestArgs<ScanQrCodeNavigationArgs>();
35 this.ContentPageModel = ViewModel;
37 this.navigationComplete = args?.NavigationCompletionSource;
39 this.LinkEntry.Entry.Keyboard = Keyboard.Url;
40 this.LinkEntry.Entry.IsSpellCheckEnabled =
false;
41 this.LinkEntry.Entry.IsTextPredictionEnabled =
false;
43 StateContainer.SetCurrentState(this.GridWithAnimation,
"AutomaticScan");
45 this.CameraBarcodeReaderView.IsDetecting =
false;
46 this.CameraBarcodeReaderView.Options =
new BarcodeReaderOptions
48 Formats = BarcodeFormats.TwoDimensional,
55 ViewModel.DoSwitchMode(
true);
62 await base.OnAppearingAsync();
64 if (this.navigationComplete is not
null)
65 await this.navigationComplete.Task;
67 this.CameraBarcodeReaderView.IsDetecting =
true;
68 WeakReferenceMessenger.Default.Register<
KeyboardSizeMessage>(
this, this.HandleKeyboardSizeMessage);
74 await MainThread.InvokeOnMainThreadAsync(this.CloseCamera);
79 await base.OnDisappearingAsync();
96 this.CameraBarcodeReaderView.IsDetecting =
false;
98 ICameraInternal? preview = await GetCameraPreview(this.CameraBarcodeReaderView);
107 return Task.CompletedTask;
117 private static async Task<ICameraInternal?> GetCameraPreview(CameraBarcodeReaderView cameraBarcodeReaderView)
120 PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>();
121 if (status == PermissionStatus.Denied)
124 BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
125 PropertyInfo? strongHandlerProperty = typeof(CameraBarcodeReaderView).GetProperty(
"StrongHandler", bindingFlags);
126 CameraBarcodeReaderViewHandler? cameraBarcodeReaderViewHandler = strongHandlerProperty?.GetValue(cameraBarcodeReaderView) as CameraBarcodeReaderViewHandler;
127 FieldInfo? manageField = typeof(CameraBarcodeReaderViewHandler).GetField(
"cameraManager", bindingFlags);
128 object? cameraManager = manageField?.GetValue(cameraBarcodeReaderViewHandler);
129 FieldInfo? cameraPreviewField = typeof(CameraBarcodeReaderViewHandler).Assembly.GetType(
"ZXing.Net.Maui.CameraManager")?.GetField(
"cameraPreview", bindingFlags);
130 Preview? preview = cameraPreviewField?.GetValue(cameraManager) as Preview;
132 return preview?.Camera;
137 private readonly TaskCompletionSource<bool>? navigationComplete;
139 private async
void HandleKeyboardSizeMessage(
object Recipient,
KeyboardSizeMessage Message)
141 await this.Dispatcher.DispatchAsync(() =>
144 if (DeviceInfo.Platform == DevicePlatform.iOS)
146 Thickness SafeInsets = this.On<iOS>().SafeAreaInsets();
147 Bottom = SafeInsets.Bottom;
149 Thickness Margin = new(0, 0, 0, Message.KeyboardSize - Bottom);
150 this.ManualScanGrid.Margin = Margin;
157 private async Task SwitchMode()
159 await this.Dispatcher.DispatchAsync(async () =>
163 string CurrentState = StateContainer.GetCurrentState(this.GridWithAnimation);
164 bool IsAutomaticScan =
string.Equals(CurrentState,
"AutomaticScan", StringComparison.OrdinalIgnoreCase);
166 if (!IsAutomaticScan)
167 this.LinkEntry.Entry.Unfocus();
170 this.CameraBarcodeReaderView.IsTorchOn = false;
171 this.CameraBarcodeReaderView.IsDetecting = false;
174 DateTime Start = DateTime.Now;
176 while (!StateContainer.GetCanStateChange(
this.GridWithAnimation) && DateTime.Now.Subtract(Start).TotalSeconds < 2)
177 await Task.Delay(100);
179 await StateContainer.ChangeStateWithAnimation(
this.GridWithAnimation,
180 IsAutomaticScan ?
"ManualScan" :
"AutomaticScan", CancellationToken.None);
182 ScanQrCodeViewModel ViewModel =
this.ViewModel<ScanQrCodeViewModel>();
183 await ViewModel.DoSwitchMode(IsAutomaticScan);
186 this.LinkEntry.Entry.Focus();
190 if (this.CameraBarcodeReaderView.CameraLocation == CameraLocation.Rear)
192 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
193 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
197 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
198 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
201 this.CameraBarcodeReaderView.IsDetecting =
true;
212 private void SwitchCamera()
214 this.CameraBarcodeReaderView.IsTorchOn =
false;
216 if (this.CameraBarcodeReaderView.CameraLocation == CameraLocation.Rear)
217 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
219 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
223 private void SwitchTorch()
225 if (this.CameraBarcodeReaderView.IsTorchOn)
226 this.CameraBarcodeReaderView.IsTorchOn =
false;
228 this.CameraBarcodeReaderView.IsTorchOn =
true;
234 private static bool CanPickPhoto() =>
false;
236 [RelayCommand (CanExecute = nameof(CanPickPhoto))]
237 private async Task PickPhoto()
239 FileResult? result = await MediaPicker.PickPhotoAsync();
245 Console.WriteLine($
"Picked photo {result.FullPath}");
246 await
using Stream stream = await result.OpenReadAsync();
247 Bitmap? bitmap = await BitmapFactory.DecodeStreamAsync(stream);
248 Console.WriteLine($
"Loaded photo {result.FullPath}");
252 int width = bitmap.Width;
253 int height = bitmap.Height;
254 int[] pixels =
new int[width * height];
255 bitmap.GetPixels(pixels, 0, width, 0, 0, width, height);
258 ByteBuffer byteBuffer = ByteBuffer.Allocate(pixels.Length *
sizeof(
int));
259 Console.WriteLine($
"{pixels.Length * sizeof(int)} : buffer: {byteBuffer.Capacity()}");
260 byteBuffer.AsIntBuffer().Put(pixels);
264 PixelBufferHolder data =
new()
266 Size =
new Size(width, height),
270 ZXingBarcodeReader reader =
new();
271 BarcodeReaderOptions options =
new()
276 Formats = BarcodeFormat.QrCode,
279 reader.Options = options;
281 BarcodeResult[]? scanned = reader.Decode(data);
284 foreach (BarcodeResult item
in scanned)
286 Console.WriteLine($
"Barcode found: {item.Value}");
291 Console.WriteLine(
"No barcode found");
299 private async
void CameraBarcodeReaderView_BarcodesDetected(
object sender, BarcodeDetectionEventArgs e)
301 string? Result = (e.Results.Length > 0) ? e.Results[0].Value :
null;
303 await
this.Dispatcher.DispatchAsync(async () =>
305 ScanQrCodeViewModel ViewModel = this.ViewModel<ScanQrCodeViewModel>();
306 await ViewModel.SetScannedText(Result);
Base class that references services in the app.
static ILogService LogService
Log service.
static IUiService UiService
Service serializing and managing UI-related tasks.
A page to display for scanning of a QR code, either automatically via the camera, or by entering the ...
override async Task OnAppearingAsync()
ScanQrCodePage()
Creates a new instance of the ScanQrCodePage class.
override async Task OnDisappearingAsync()
The view model to bind to when scanning a QR code.
class KeyboardSizeMessage(float KeyboardSize)
Keyboard size change message