Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ScanQrCodePage.xaml.cs
1
2using CommunityToolkit.Maui.Layouts;
3using CommunityToolkit.Mvvm.Input;
4using CommunityToolkit.Mvvm.Messaging;
5using Microsoft.Maui.Controls.PlatformConfiguration;
6using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
8using ZXing.Net.Maui;
9#if ANDROID
10using Android.Graphics;
11using AndroidX.Camera.Core;
12using AndroidX.Camera.Core.Impl;
13using Java.Nio;
14using System.Reflection;
15using ZXing.Net.Maui.Controls;
16using ZXing.Net.Maui.Readers;
17#endif
18
20{
24 public partial class ScanQrCodePage
25 {
30 {
31 this.InitializeComponent();
32
33 ScanQrCodeNavigationArgs? args = ServiceRef.UiService.PopLatestArgs<ScanQrCodeNavigationArgs>();
34 ScanQrCodeViewModel ViewModel = new(args);
35 this.ContentPageModel = ViewModel;
36
37 this.navigationComplete = args?.NavigationCompletionSource;
38
39 this.LinkEntry.Entry.Keyboard = Keyboard.Url;
40 this.LinkEntry.Entry.IsSpellCheckEnabled = false;
41 this.LinkEntry.Entry.IsTextPredictionEnabled = false;
42
43 StateContainer.SetCurrentState(this.GridWithAnimation, "AutomaticScan");
44
45 this.CameraBarcodeReaderView.IsDetecting = false;
46 this.CameraBarcodeReaderView.Options = new BarcodeReaderOptions
47 {
48 Formats = BarcodeFormats.TwoDimensional,
49 AutoRotate = true,
50 TryHarder = true,
51 TryInverted = true,
52 Multiple = false,
53 };
54
55 ViewModel.DoSwitchMode(true);
56 }
57
58
60 protected override async Task OnAppearingAsync()
61 {
62 await base.OnAppearingAsync();
63
64 if (this.navigationComplete is not null)
65 await this.navigationComplete.Task;
66
67 this.CameraBarcodeReaderView.IsDetecting = true;
68 WeakReferenceMessenger.Default.Register<KeyboardSizeMessage>(this, this.HandleKeyboardSizeMessage);
69 }
70
72 protected override async Task OnDisappearingAsync()
73 {
74 await MainThread.InvokeOnMainThreadAsync(this.CloseCamera);
75
76
77 WeakReferenceMessenger.Default.Unregister<KeyboardSizeMessage>(this);
78
79 await base.OnDisappearingAsync();
80 }
81
88 private
89#if ANDROID
90 async
91#endif
92 Task CloseCamera()
93 {
94 try
95 {
96 this.CameraBarcodeReaderView.IsDetecting = false;
97#if ANDROID
98 ICameraInternal? preview = await GetCameraPreview(this.CameraBarcodeReaderView);
99 preview?.Close();
100#endif
101 }
102 catch (Exception e)
103 {
104 ServiceRef.LogService.LogException(e);
105 }
106#if !ANDROID
107 return Task.CompletedTask;
108#endif
109 }
110#if ANDROID
117 private static async Task<ICameraInternal?> GetCameraPreview(CameraBarcodeReaderView cameraBarcodeReaderView)
118 {
119
120 PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>();
121 if (status == PermissionStatus.Denied)
122 return null;
123
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;
131
132 return preview?.Camera;
133 }
134#endif
135
136
137 private readonly TaskCompletionSource<bool>? navigationComplete;
138
139 private async void HandleKeyboardSizeMessage(object Recipient, KeyboardSizeMessage Message)
140 {
141 await this.Dispatcher.DispatchAsync(() =>
142 {
143 double Bottom = 0;
144 if (DeviceInfo.Platform == DevicePlatform.iOS)
145 {
146 Thickness SafeInsets = this.On<iOS>().SafeAreaInsets();
147 Bottom = SafeInsets.Bottom;
148
149 Thickness Margin = new(0, 0, 0, Message.KeyboardSize - Bottom);
150 this.ManualScanGrid.Margin = Margin;
151 }
152
153 });
154 }
155
156 [RelayCommand]
157 private async Task SwitchMode()
158 {
159 await this.Dispatcher.DispatchAsync(async () =>
160 {
161 try
162 {
163 string CurrentState = StateContainer.GetCurrentState(this.GridWithAnimation);
164 bool IsAutomaticScan = string.Equals(CurrentState, "AutomaticScan", StringComparison.OrdinalIgnoreCase);
165
166 if (!IsAutomaticScan)
167 this.LinkEntry.Entry.Unfocus();
168 else
169 {
170 this.CameraBarcodeReaderView.IsTorchOn = false;
171 this.CameraBarcodeReaderView.IsDetecting = false;
172 }
173
174 DateTime Start = DateTime.Now;
175
176 while (!StateContainer.GetCanStateChange(this.GridWithAnimation) && DateTime.Now.Subtract(Start).TotalSeconds < 2)
177 await Task.Delay(100);
178
179 await StateContainer.ChangeStateWithAnimation(this.GridWithAnimation,
180 IsAutomaticScan ? "ManualScan" : "AutomaticScan", CancellationToken.None);
181
182 ScanQrCodeViewModel ViewModel = this.ViewModel<ScanQrCodeViewModel>();
183 await ViewModel.DoSwitchMode(IsAutomaticScan);
184
185 if (IsAutomaticScan)
186 this.LinkEntry.Entry.Focus();
187 else
188 {
189 // reinitialize the camera by switching it
190 if (this.CameraBarcodeReaderView.CameraLocation == CameraLocation.Rear)
191 {
192 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
193 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
194 }
195 else
196 {
197 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
198 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
199 }
200
201 this.CameraBarcodeReaderView.IsDetecting = true;
202 }
203 }
204 catch (Exception ex)
205 {
206 ServiceRef.LogService.LogException(ex);
207 }
208 });
209 }
210
211 [RelayCommand]
212 private void SwitchCamera()
213 {
214 this.CameraBarcodeReaderView.IsTorchOn = false;
215
216 if (this.CameraBarcodeReaderView.CameraLocation == CameraLocation.Rear)
217 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
218 else
219 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
220 }
221
222 [RelayCommand]
223 private void SwitchTorch()
224 {
225 if (this.CameraBarcodeReaderView.IsTorchOn)
226 this.CameraBarcodeReaderView.IsTorchOn = false;
227 else
228 this.CameraBarcodeReaderView.IsTorchOn = true;
229 }
230
234 private static bool CanPickPhoto() => false;
235
236 [RelayCommand (CanExecute = nameof(CanPickPhoto))]
237 private async Task PickPhoto()
238 {
239 FileResult? result = await MediaPicker.PickPhotoAsync();
240 if (result is null)
241 return;
242
243#if ANDROID
244 // For Android, convert the picked image to a Bitmap and then to pixel data
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}");
249
250 if (bitmap != null)
251 {
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);
256
257 // Convert pixel data to ByteBuffer
258 ByteBuffer byteBuffer = ByteBuffer.Allocate(pixels.Length * sizeof(int));
259 Console.WriteLine($"{pixels.Length * sizeof(int)} : buffer: {byteBuffer.Capacity()}");
260 byteBuffer.AsIntBuffer().Put(pixels);
261 byteBuffer.Flip();
262
263 // Initialize PixelBufferHolder
264 PixelBufferHolder data = new()
265 {
266 Size = new Size(width, height),
267 Data = byteBuffer
268 };
269
270 ZXingBarcodeReader reader = new();
271 BarcodeReaderOptions options = new()
272 {
273 AutoRotate = true,
274 TryHarder = true,
275 TryInverted = true,
276 Formats = BarcodeFormat.QrCode,
277 Multiple = false
278 };
279 reader.Options = options;
280
281 BarcodeResult[]? scanned = reader.Decode(data);
282 if (scanned != null)
283 {
284 foreach (BarcodeResult item in scanned)
285 {
286 Console.WriteLine($"Barcode found: {item.Value}");
287 }
288 }
289 else
290 {
291 Console.WriteLine("No barcode found");
292 }
293 }
294#elif IOS
295 return;
296#endif
297 }
298
299 private async void CameraBarcodeReaderView_BarcodesDetected(object sender, BarcodeDetectionEventArgs e)
300 {
301 string? Result = (e.Results.Length > 0) ? e.Results[0].Value : null;
302
303 await this.Dispatcher.DispatchAsync(async () =>
304 {
305 ScanQrCodeViewModel ViewModel = this.ViewModel<ScanQrCodeViewModel>();
306 await ViewModel.SetScannedText(Result);
307 });
308 }
309 }
310}
Base class that references services in the app.
Definition: ServiceRef.cs:31
static ILogService LogService
Log service.
Definition: ServiceRef.cs:91
static IUiService UiService
Service serializing and managing UI-related tasks.
Definition: ServiceRef.cs:55
A page to display for scanning of a QR code, either automatically via the camera, or by entering the ...
ScanQrCodePage()
Creates a new instance of the ScanQrCodePage class.
The view model to bind to when scanning a QR code.
class KeyboardSizeMessage(float KeyboardSize)
Keyboard size change message
Definition: Messages.cs:19