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;
3// using CommunityToolkit.Mvvm.Input; // Removed page-level commands; commands now reside in ViewModel
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 {
26 public ScanQrCodePage()
27 {
28 // Create VM (it will PopLatestArgs internally)
29 ScanQrCodeViewModel vm = new();
30 this.BindingContext = vm; // set before InitializeComponent for compiled bindings
31
32 this.InitializeComponent();
33
34 // Post-XAML control configuration
35 this.LinkEntry.Keyboard = Keyboard.Url;
36 this.LinkEntry.IsSpellCheckEnabled = false;
37 this.LinkEntry.IsTextPredictionEnabled = false;
38
39 StateContainer.SetCurrentState(this.GridWithAnimation, "AutomaticScan");
40
41 this.CameraBarcodeReaderView.IsDetecting = false;
42 this.CameraBarcodeReaderView.Options = new BarcodeReaderOptions
43 {
44 Formats = BarcodeFormats.TwoDimensional,
45 AutoRotate = true,
46 TryHarder = true,
47 TryInverted = true,
48 Multiple = false,
49 };
50
51 vm.DoSwitchMode(true);
52 }
53
54
56 public override async Task OnAppearingAsync()
57 {
58 // Base Appearing executes ViewModel lifecycle
59 await base.OnAppearingAsync();
60
61 // Sync initial states from VM
62 if (this.BindingContext is ScanQrCodeViewModel vm)
63 {
64 this.ApplyState(vm.IsAutomaticScan, initial: true);
65 this.CameraBarcodeReaderView.IsTorchOn = vm.IsTorchOn;
66 this.CameraBarcodeReaderView.CameraLocation = vm.CameraLocation;
67 vm.PropertyChanged += this.VmOnPropertyChanged;
68 }
69 }
70
72 public override async Task OnDisappearingAsync()
73 {
74 if (this.BindingContext is ScanQrCodeViewModel vm)
75 vm.PropertyChanged -= this.VmOnPropertyChanged;
76 await MainThread.InvokeOnMainThreadAsync(this.CloseCamera);
77 await base.OnDisappearingAsync();
78 }
79
80 private async void VmOnPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
81 {
82 if (sender is not ScanQrCodeViewModel vm)
83 return;
84
85 switch (e.PropertyName)
86 {
87 case nameof(ScanQrCodeViewModel.IsAutomaticScan):
88 await this.Dispatcher.DispatchAsync(() => this.ApplyState(vm.IsAutomaticScan));
89 break;
90 case nameof(ScanQrCodeViewModel.IsTorchOn):
91 this.CameraBarcodeReaderView.IsTorchOn = vm.IsTorchOn;
92 break;
93 case nameof(ScanQrCodeViewModel.IsDetecting):
94 this.CameraBarcodeReaderView.IsDetecting = vm.IsDetecting;
95 break;
96 case nameof(ScanQrCodeViewModel.CameraLocation):
97 this.CameraBarcodeReaderView.CameraLocation = vm.CameraLocation;
98 break;
99 }
100 }
101
102 private async void ApplyState(bool isAutomatic, bool initial = false)
103 {
104 try
105 {
106 string current = StateContainer.GetCurrentState(this.GridWithAnimation);
107 bool currentlyAutomatic = string.Equals(current, "AutomaticScan", StringComparison.OrdinalIgnoreCase);
108 if (currentlyAutomatic == isAutomatic && !initial)
109 return;
110
111 if (initial)
112 {
113 // Initial setup: avoid animation & camera flip hack to prevent black screen
114 if (isAutomatic)
115 {
116 if (!currentlyAutomatic)
117 StateContainer.SetCurrentState(this.GridWithAnimation, "AutomaticScan");
118 this.LinkEntry.Unfocus();
119 // slight delay to allow native camera initialization before enabling detection
120 await Task.Delay(250);
121 this.CameraBarcodeReaderView.IsDetecting = true;
122 }
123 else
124 {
125 StateContainer.SetCurrentState(this.GridWithAnimation, "ManualScan");
126 this.CameraBarcodeReaderView.IsTorchOn = false;
127 this.CameraBarcodeReaderView.IsDetecting = false;
128 this.LinkEntry.Focus();
129 }
130 return;
131 }
132
133 if (!isAutomatic)
134 {
135 // Enter manual: stop camera
136 this.CameraBarcodeReaderView.IsTorchOn = false;
137 this.CameraBarcodeReaderView.IsDetecting = false;
138 await StateContainer.ChangeStateWithAnimation(this.GridWithAnimation, "ManualScan", CancellationToken.None);
139 this.LinkEntry.Focus();
140 }
141 else
142 {
143 this.LinkEntry.Unfocus();
144 // Re-init camera by flipping (runtime toggle only)
145 if (this.CameraBarcodeReaderView.CameraLocation == CameraLocation.Rear)
146 {
147 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
148 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
149 }
150 else
151 {
152 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Rear;
153 this.CameraBarcodeReaderView.CameraLocation = CameraLocation.Front;
154 }
155 await StateContainer.ChangeStateWithAnimation(this.GridWithAnimation, "AutomaticScan", CancellationToken.None);
156 this.CameraBarcodeReaderView.IsDetecting = true;
157 }
158 }
159 catch (Exception ex)
160 {
161 ServiceRef.LogService.LogException(ex);
162 }
163 }
164
171 private
172#if ANDROID
173 async
174#endif
175 Task CloseCamera()
176 {
177 try
178 {
179 this.CameraBarcodeReaderView.IsDetecting = false;
180#if ANDROID
181 ICameraInternal? preview = await GetCameraPreview(this.CameraBarcodeReaderView);
182 preview?.Close();
183#endif
184 }
185 catch (Exception e)
186 {
187 ServiceRef.LogService.LogException(e);
188 }
189#if !ANDROID
190 return Task.CompletedTask;
191#endif
192 }
193#if ANDROID
200 private static async Task<ICameraInternal?> GetCameraPreview(CameraBarcodeReaderView cameraBarcodeReaderView)
201 {
202
203 PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>();
204 if (status == PermissionStatus.Denied)
205 return null;
206
207 BindingFlags BindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
208 PropertyInfo? StrongHandlerProperty = typeof(CameraBarcodeReaderView).GetProperty("StrongHandler", BindingFlags);
209 CameraBarcodeReaderViewHandler? CameraBarcodeReaderViewHandler = StrongHandlerProperty?.GetValue(cameraBarcodeReaderView) as CameraBarcodeReaderViewHandler;
210 FieldInfo? ManageField = typeof(CameraBarcodeReaderViewHandler).GetField("cameraManager", BindingFlags);
211 object? CameraManager = ManageField?.GetValue(CameraBarcodeReaderViewHandler);
212 FieldInfo? CameraPreviewField = typeof(CameraBarcodeReaderViewHandler).Assembly.GetType("ZXing.Net.Maui.CameraManager")?.GetField("cameraPreview", BindingFlags);
213 Preview? Preview = CameraPreviewField?.GetValue(CameraManager) as Preview;
214
215 return Preview?.Camera;
216 }
217#endif
218
219
220 private async void CameraBarcodeReaderView_BarcodesDetected(object sender, BarcodeDetectionEventArgs e)
221 {
222 string? Result = (e.Results.Length > 0) ? e.Results[0].Value : null;
223
224 await this.Dispatcher.DispatchAsync(async () =>
225 {
226 ScanQrCodeViewModel ViewModel = this.ViewModel<ScanQrCodeViewModel>();
227 await ViewModel.SetScannedText(Result);
228 });
229 }
230 }
231}
Base class that references services in the app.
Definition: ServiceRef.cs:43
static ILogService LogService
Log service.
Definition: ServiceRef.cs:214
A page to display for scanning of a QR code, either automatically via the camera, or by entering the ...
The view model to bind to when scanning a QR code.