Skip to content

Commit e71d231

Browse files
committed
feat(qr-code): enhance QR code scanner with camera switching
- Add support for multiple cameras and camera switching in QR code component - Increase QR code box size from 200x200 to 250x250 for better scanning - Implement start and stop methods to properly manage scanner lifecycle - Add buttons for switching camera and stopping scanner in QR code page - Refactor QR code scanner layout and controls for improved user interaction - Fix conditional rendering logic for scan and manual entry buttons - Reset loading state when starting manual code entry to avoid conflicts
1 parent 6a3207c commit e71d231

File tree

2 files changed

+69
-47
lines changed

2 files changed

+69
-47
lines changed

mobile/src/app/qr-code/ngx-html5-qrcode.component.ts

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,65 @@ import {
22
AfterViewInit,
33
Component,
44
ElementRef,
5+
EventEmitter,
6+
Input,
57
OnDestroy,
6-
OnInit,
7-
Renderer2,
8-
ViewChild,
98
Output,
10-
Input,
11-
EventEmitter,
9+
ViewChild,
1210
} from '@angular/core';
13-
import { Html5Qrcode } from 'html5-qrcode';
14-
import { Html5QrcodeCameraScanConfig } from 'html5-qrcode/esm/html5-qrcode';
11+
import { CameraDevice, Html5Qrcode } from 'html5-qrcode';
1512
import { Html5QrcodeResult } from 'html5-qrcode/esm/core';
13+
import { Html5QrcodeCameraScanConfig } from 'html5-qrcode/esm/html5-qrcode';
1614

1715
@Component({
1816
selector: 'html5-qrcode',
1917
template: ` <div #reader id="reader" width="600px"></div> `,
2018
styles: [],
2119
})
22-
export class NgxHtml5QrcodeComponent
23-
implements OnInit, AfterViewInit, OnDestroy
24-
{
20+
export class NgxHtml5QrcodeComponent implements AfterViewInit, OnDestroy {
2521
@ViewChild('reader') reader: ElementRef | undefined;
2622
html5QrCode!: Html5Qrcode;
2723
cameraId: string = '';
24+
cameraIndex = 0;
25+
cameras: CameraDevice[] = [];
2826

2927
@Input() useFrontCamera: boolean = false;
3028
@Input() config: Html5QrcodeCameraScanConfig = {
3129
fps: 10,
32-
qrbox: { width: 200, height: 200 },
30+
qrbox: { width: 250, height: 250 },
3331
};
3432
@Output() decodedText: EventEmitter<string> = new EventEmitter<string>();
3533
@Output() decodedResult: EventEmitter<Html5QrcodeResult> =
3634
new EventEmitter<Html5QrcodeResult>();
3735

38-
constructor() {}
39-
40-
ngOnInit(): void {}
41-
4236
ngAfterViewInit() {
4337
// This method will trigger user permissions
4438
Html5Qrcode.getCameras()
4539
.then((devices) => {
46-
if (devices && devices.length) {
47-
// .. use this to start scanning.
48-
this.cameraId = this.useFrontCamera ? devices[1].id : devices[0].id;
49-
this.startHtmlQrCode();
50-
}
40+
this.cameras = devices || [];
41+
this.switchCamera(0);
5142
})
5243
.catch((err) => {
5344
console.log(err);
5445
});
5546
}
5647

48+
switchCamera(cameraIndex?: number) {
49+
if (this.cameras && this.cameras.length) {
50+
if (cameraIndex === undefined) {
51+
this.cameraIndex = this.cameraIndex + 1;
52+
if (this.cameraIndex > this.cameras.length - 1) {
53+
this.cameraIndex = 0;
54+
}
55+
} else {
56+
this.cameraIndex = cameraIndex;
57+
}
58+
this.cameraId = this.cameras[this.cameraIndex].id;
59+
this.stopHtmlQrCode();
60+
this.startHtmlQrCode();
61+
}
62+
}
63+
5764
qrCodeSuccessCallback(decodedText: any, decodedResult: Html5QrcodeResult) {
5865
/* handle success */
5966
this.decodedText.emit(decodedText);
@@ -62,10 +69,10 @@ export class NgxHtml5QrcodeComponent
6269

6370
qrCodeErrorCallback(errorMessage: any) {
6471
/* handle success */
65-
// console.error(errorMessage);
72+
// console.error(errorMessage);
6673
}
6774

68-
startHtmlQrCode() {
75+
private startHtmlQrCode() {
6976
this.html5QrCode = new Html5Qrcode(this.reader?.nativeElement?.id);
7077

7178
this.html5QrCode
@@ -82,13 +89,15 @@ export class NgxHtml5QrcodeComponent
8289
}
8390

8491
ngOnDestroy() {
92+
this.stopHtmlQrCode();
93+
}
94+
95+
private stopHtmlQrCode() {
8596
this.html5QrCode
86-
.stop()
97+
?.stop()
8798
.then((ignore) => {
8899
// QR Code scanning is stopped.
89100
})
90-
.catch((err) => {
91-
// Stop failed, handle it.
92-
});
101+
.catch((err) => {});
93102
}
94103
}

mobile/src/app/qr-code/qr-code.page.ts

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,24 @@ interface QrCodeData {
192192
<div style="padding: 20px; text-align: center;">
193193
@if (showScanner$ | async) {
194194
<div style="width: 100%; height:100%; ">
195-
<html5-qrcode (decodedText)="onDecodedText($event)"></html5-qrcode>
195+
<div style="width: 100%; height: 80%;">
196+
<html5-qrcode
197+
(decodedText)="onDecodedText($event)"
198+
style="width: 100%; height: 90%;"
199+
#qrcode
200+
>
201+
</html5-qrcode>
202+
</div>
203+
<div
204+
style="display: flex; justify-content: center;padding-top: 10px; gap: 10px;"
205+
>
206+
<ion-button size="small" (click)="qrcode.switchCamera()">
207+
Switch camera
208+
</ion-button>
209+
<ion-button size="small" (click)="stopScan()">
210+
Stop camera
211+
</ion-button>
212+
</div>
196213
</div>
197214
} @if (isLoading$ | async) {
198215
<div
@@ -210,27 +227,21 @@ interface QrCodeData {
210227
</ion-button>
211228
</ion-card-content>
212229
</ion-card>
213-
} @else { @if ((showScanner$|async)===false) {
214-
<ion-button (click)="startScan()">
215-
<ion-icon name="scan-outline" slot="start"></ion-icon>
216-
Scan QR Code
217-
</ion-button>
218-
<br />
219230
} @else {
220-
<ion-button (click)="stopScan()">
221-
<ion-icon name="scan-outline" slot="start"></ion-icon>
222-
Stop scan QR Code
223-
</ion-button>
224-
<br />
225-
}
226-
<ion-button
227-
(click)="startManualCodeEntry()"
228-
fill="outline"
229-
style="margin-top: 10px;"
231+
<div
232+
style="display: flex; justify-content: center;padding-top: 10px; gap: 10px;"
230233
>
231-
<ion-icon name="keypad-outline" slot="start"></ion-icon>
232-
Enter Code Manually
233-
</ion-button>
234+
@if ((showScanner$|async)===false) {
235+
<ion-button (click)="startScan()">
236+
<ion-icon name="scan-outline" slot="start"></ion-icon>
237+
Scan QR
238+
</ion-button>
239+
}
240+
<ion-button (click)="startManualCodeEntry()" fill="outline">
241+
<ion-icon name="keypad-outline" slot="start"></ion-icon>
242+
Enter Code
243+
</ion-button>
244+
</div>
234245
}
235246
</div>
236247
</app-explore-container>
@@ -305,7 +316,7 @@ export class QrCodePage {
305316
}
306317

307318
private link(code: string) {
308-
if (this.isLoading$.value || !this.showScanner$.value) {
319+
if (this.isLoading$.value) {
309320
return of(null);
310321
}
311322

@@ -362,6 +373,8 @@ export class QrCodePage {
362373

363374
async startManualCodeEntry() {
364375
this.showScanner$.next(false);
376+
this.isLoading$.next(false);
377+
365378
const alert = await this.alertController.create({
366379
header: 'Enter Code',
367380
inputs: [

0 commit comments

Comments
 (0)