EddyVerbruggen / nativescript-plugin-firebase

:fire: NativeScript plugin for Firebase
https://firebase.google.com
MIT License
1.01k stars 446 forks source link

Stop barcode scanner after first set of scanned images received #828

Closed phatakrajan closed 5 years ago

phatakrajan commented 6 years ago

I have implemented barcode scanner as suggested in ML Kit documentation. Here is my HTML

<side-drawer-page>
    <GridLayout>
        <MLKitBarcodeScanner #scanner *ngIf="!scanDone" width="100%" height="100%" formats="QR_CODE, EAN_8, EAN_13" android:processEveryNthFrame="5"
            ios:processEveryNthFrame="10" (scanResult)="onBarcodeScanResult($event)">
        </MLKitBarcodeScanner>

        <GridLayout rows="*, 320, *" columns="*, 5/6*, *">
            <Label class="mask" row="0" col="0" colSpan="3"></Label>
            <Label class="mask" row="2" col="0" colSpan="3"></Label>
            <Label class="mask" row="1" col="0"></Label>
            <Label class="mask" row="1" col="2"></Label>
            <GridLayout row="1" col="1" rows="1/6*, *, 1/6*" columns="1/6*, *, 1/6*">
                <Label class="frame-top-left" row="0" col="0"></Label>
                <Label class="frame-top-right" row="0" col="2"></Label>
                <Label class="frame-bottom-left" row="2" col="0"></Label>
                <Label class="frame-bottom-right" row="2" col="2"></Label>
                <StackLayout class="swing" row="0" col="0" colSpan="3">
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.1)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.2)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.3)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.4)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.5)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.6)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.7)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.8)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 0.9)"></Label>
                    <Label height="1" marginBottom="1" borderBottomWidth="1" borderColor="rgba(81, 184, 237, 1)"></Label>
                </StackLayout>
            </GridLayout>
            <Label row="0" col="1" class="mdi icon" [text]="'mdi-vpn-key' | fonticon" [row]="i" column="0"></Label>
            <!-- <Label row="0" col="1" class="text-center c-white" textWrap="true" verticalAlignment="center" text="The scanner has been configured to detect QR codes, EAN 8 and EAN 13. It processes every 5th frame (default 10). These settings can be tweaked in your usage of the plugin."></Label> -->
            <ListView row="2" col="0" colSpan="3" [items]="barcodes" class="m-t-20" backgroundColor="transparent">
                <ng-template let-item="item">
                    <GridLayout columns="2*, 3*">
                        <Label col="0" class="mlkit-result" textWrap="true" [text]="item.format"></Label>
                        <Label col="1" class="mlkit-result" textWrap="true" [text]="item.value"></Label>
                    </GridLayout>
                </ng-template>
            </ListView>
        </GridLayout>
    </GridLayout>
</side-drawer-page>

And here is my code

import { Component, OnInit, AfterViewInit, ViewContainerRef, ViewChild, ElementRef } from "@angular/core";

import { FirebaseService } from "~/service/firebase.service";
import { MLKitScanBarcodesOnDeviceResult } from "nativescript-plugin-firebase/mlkit/barcodescanning";
import { ScanData } from "~/models/scanData";
import { ScanDataService } from "~/service/scandata.service";
import { ModalDialogService } from "nativescript-angular/directives/dialogs";
import { ShowScanValueComponent } from "~/show-scan-value/show-scan-value.component";
import { Router } from "@angular/router";
import { MLKitBarcodeScanner } from "nativescript-plugin-firebase/mlkit/barcodescanning/barcodescanning-common";

@Component({
    selector: "ns-items",
    moduleId: module.id,
    templateUrl: "./scanitems.component.html",
})
export class ScanItemsComponent implements OnInit, AfterViewInit {

    @ViewChild('scanner') scannerEle: ElementRef;
    barcodes: ScanData[];

    scanDone: boolean = false;
    scanner: MLKitBarcodeScanner ;

    // This pattern makes use of Angular’s dependency injection implementation to inject an instance of the ItemService service into this class. 
    // Angular knows about this service because it is included in your app’s main NgModule, defined in app.module.ts.
    constructor(
        private firebaseService: FirebaseService,
        private scanDataService: ScanDataService,
        private _vcRef: ViewContainerRef,
        private _modal: ModalDialogService,
        private _router: Router
    ) {
    }

    ngOnInit(): void {
    }

    ngAfterViewInit(): void {
        setTimeout(() => {
            this.firebaseService.createBanner();
        }, 3000);
    }

    onBarcodeScanResult(event: any): void {
        const result: MLKitScanBarcodesOnDeviceResult = event.value;
        this.barcodes = result.barcodes;

        if (this.barcodes.length > 0) {
            this.scanner = this.scannerEle.nativeElement;

            this.scanner.disposeNativeView();

            let options = {
                context: { barcodes: this.barcodes },
                fullscreen: false,
                viewContainerRef: this._vcRef,
                backdrop: "static"
            };

            this._modal.showModal(ShowScanValueComponent, options).then((result) => {

                if (result === 1){
                    this.barcodes.forEach(barcode => {
                        let scandata: ScanData = barcode;
                        scandata.scanDate = (new Date()).toISOString();
                        this.scanDataService.insert(scandata);
                    });

                    this._router.navigate([
                        '/home'
                    ]);
                }                 
            });

        }
    }
}

I am routing to a different page upon successfully receiving the barcodes. However i still keep getting scanResult events and automatically navigate back to the scanning screen. I also tried to dispose the object upon receiving first set of barcodes/removing the event listener. However both does not work. Not sure why events are being emitted upon movement.

EddyVerbruggen commented 6 years ago

When you navigate away from the scanner page, are you sure the page is destroyed? That should also destroy the scanner object. Can you check that for me, please?

If the page is actually destroyed and you still receive updates, then it'd be very helpful for me to know whether you experience this on iOS, Android, or both?

phatakrajan commented 6 years ago

@EddyVerbruggen The page is not getting destroyed since i am navigating using < page-router-outlet > and i think when i move from Component 1 -> 2, it just caches it. Is there any way i should destroy page manually? or only scanner control for that matter? i tried that by calling disposeNativeView.

I am currently working only on Android. Not tested on iOS.

phatakrajan commented 6 years ago

@EddyVerbruggen I explicitly unloaded the control on getting first scanned barcode.

this.scanner = this.scannerEle.nativeElement;
          this._page.unloadView(this.scanner); 

Is this the right way to do it? Or will there be any better way to unload the control?

EddyVerbruggen commented 6 years ago

Did that solve the issue? (I'm on vacation, so a bit hard to check myself).

phatakrajan commented 6 years ago

Not completely. I am facing issue if i want to show the values in a modal dialog on same activity. I am unable to close object properly before showing a modal dialog and keep getting the events. However we can take a look at the issue once you are back from vacation

avallem commented 5 years ago

In documentation does not explain if exist some method or property to stop scanner, Its would be helpfully implement this functionallity to setup the scanner or prevent firing events of Scanning Result multiple times.

At this time the solution is destroy the view after navigate?

This is my code (NativeScript Vue) and 'navigateBack' its firing twice (or more)

          if(typeof args.value.barcodes[0] !== 'undefined'){
                if(args.value.barcodes[0].format == 'QR_CODE'){
                    console.log(args.value.barcodes[0].value)

                    this.$navigateBack({props:{dispenser_id:args.value.barcodes[0].value}})
                }
            }
phatakrajan commented 5 years ago

@EddyVerbruggen Can you please let us know on how this issue can be fixed? We really don't know on how to stop firing this events.

EddyVerbruggen commented 5 years ago

I've just published 7.2.0 which adds a bindable pause property to the scanner UI widget. Docs here, and the demo has been updated as well:

https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/fc10aa162ed4c96bb035a99a53fe8d206c375908/demo-ng/app/tabs/mlkit/barcodescanning/barcodescanning.component.html#L13

https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/fc10aa162ed4c96bb035a99a53fe8d206c375908/demo-ng/app/tabs/mlkit/barcodescanning/barcodescanning.component.ts#L16

phatakrajan commented 5 years ago

Excellent :)