File

src/services/sunbirdqrscanner.service.ts

Index

Properties
Methods

Constructor

constructor(translate: TranslateService, platform: Platform, qrScannerResultHandler: QRScannerResultHandler, telemetryGeneratorService: TelemetryGeneratorService, appGlobalService: AppGlobalService, container: ContainerService, permission: AndroidPermissionsService, commonUtilService: CommonUtilService, appVersion: AppVersion, toastController: ToastController, router: Router, modalCtrl: ModalController, projectCert: ManageLearnCertificateService)
Parameters :
Name Type Optional
translate TranslateService No
platform Platform No
qrScannerResultHandler QRScannerResultHandler No
telemetryGeneratorService TelemetryGeneratorService No
appGlobalService AppGlobalService No
container ContainerService No
permission AndroidPermissionsService No
commonUtilService CommonUtilService No
appVersion AppVersion No
toastController ToastController No
router Router No
modalCtrl ModalController No
projectCert ManageLearnCertificateService No

Methods

Private generateEndEvent
generateEndEvent(pageId: string, qrData: string)
Parameters :
Name Type Optional
pageId string No
qrData string No
Returns : void
Private generateImpressionTelemetry
generateImpressionTelemetry(source, dialCode?)
Parameters :
Name Optional
source No
dialCode Yes
Returns : void
Private generateStartEvent
generateStartEvent(pageId: string)
Parameters :
Name Type Optional
pageId string No
Returns : void
Private getProfileSettingConfig
getProfileSettingConfig()
Returns : void
Private Async showInvalidCodeAlert
showInvalidCodeAlert(scannedData)
Parameters :
Name Optional
scannedData No
Returns : any
Private Async showPopover
showPopover(pageId: string)
Parameters :
Name Type Optional
pageId string No
Returns : Promise<string | undefined>
Private Async startQRScanner
startQRScanner(screenTitle: string, displayText: string, displayTextColor: string, buttonText: string, showButton: boolean, source: string)
Parameters :
Name Type Optional
screenTitle string No
displayText string No
displayTextColor string No
buttonText string No
showButton boolean No
source string No
Returns : Promise<string | undefined>
Public Async startScanner
startScanner(source: string, showButton: boolean, screenTitle, displayText, displayTextColor: string, buttonText)
Parameters :
Name Type Optional Default value
source string No
showButton boolean No false
screenTitle No this.mQRScannerText['SCAN_QR_CODE']
displayText No this.mQRScannerText['SCAN_QR_INSTRUCTION']
displayTextColor string No '#0b0b0b'
buttonText No this.mQRScannerText['NO_QR_CODE']
Returns : Promise<string | undefined>
Public stopScanner
stopScanner()
Returns : void

Properties

appName
Type : string
Default value : ''
backButtonFunc
Default value : undefined
Private isScannerActive
Default value : false
Private mQRScannerText
profile
Type : Profile
Private Readonly QR_SCANNER_TEXT
Type : []
Default value : [ 'SCAN_QR_CODE', 'SCAN_QR_INSTRUCTION', 'UNKNOWN_QR', 'NO_QR_CODE', 'CANCEL', 'TRY_AGAIN', ]
Private qrModal
Type : HTMLIonModalElement
showButton
Default value : false
source
Type : string
import { Injectable } from '@angular/core';
import { NavigationExtras, Router } from '@angular/router';
import { QrScannerIOSComponent } from '@app/app/components/qr-scanner-ios/qr-scanner-ios.component';
import { GUEST_STUDENT_TABS, GUEST_TEACHER_TABS, initTabs } from '@app/app/module.service';
import { AppGlobalService, CommonUtilService, QRScannerResultHandler, TelemetryGeneratorService } from '@app/services/';
import { AndroidPermissionsService } from '@app/services/android-permissions/android-permissions.service';
import { ContainerService } from '@app/services/container.services';
import { AppVersion } from '@ionic-native/app-version/ngx';
import { ModalController, Platform, ToastController } from '@ionic/angular';
import { TranslateService } from '@ngx-translate/core';
import { take } from 'rxjs/operators';
import { CorrelationData, Profile, ProfileType, TelemetryObject } from 'sunbird-sdk';
import { AndroidPermission, AndroidPermissionsStatus, PermissionAskedEnum } from './android-permissions/android-permission';
import {
  CorReleationDataType, Environment,
  ImpressionSubtype,
  ImpressionType,
  InteractSubtype,
  InteractType,
  Mode,
  PageId
} from './telemetry-constants';
import { ManageLearnCertificateService } from '@app/app/manage-learn/core/services/manage-learn-certificate.service';

declare const cordova;

@Injectable()
export class SunbirdQRScanner {
  profile: Profile;
  private readonly QR_SCANNER_TEXT = [
    'SCAN_QR_CODE',
    'SCAN_QR_INSTRUCTION',
    'UNKNOWN_QR',
    'NO_QR_CODE',
    'CANCEL',
    'TRY_AGAIN',
  ];
  private mQRScannerText;
  backButtonFunc = undefined;
  source: string;
  showButton = false;
  appName = '';
  private isScannerActive = false;
  private qrModal: HTMLIonModalElement
  constructor(
    private translate: TranslateService,
    private platform: Platform,
    private qrScannerResultHandler: QRScannerResultHandler,
    private telemetryGeneratorService: TelemetryGeneratorService,
    private appGlobalService: AppGlobalService,
    private container: ContainerService,
    private permission: AndroidPermissionsService,
    private commonUtilService: CommonUtilService,
    private appVersion: AppVersion,
    private toastController: ToastController,
    private router: Router,
    private modalCtrl: ModalController,
    private projectCert : ManageLearnCertificateService
  ) {
    const that = this;
    this.translate.get(this.QR_SCANNER_TEXT).subscribe((data) => {
      that.mQRScannerText = data;
    });

    this.translate.onLangChange.subscribe(() => {
      that.mQRScannerText = that.translate.instant(that.QR_SCANNER_TEXT);
    });

    this.appVersion.getAppName().then((appName: any) => this.appName = appName);
  }

  public async startScanner(
    source: string,
    showButton: boolean = false,
    screenTitle = this.mQRScannerText['SCAN_QR_CODE'],
    displayText = this.mQRScannerText['SCAN_QR_INSTRUCTION'],
    displayTextColor = '#0b0b0b',
    buttonText = this.mQRScannerText['NO_QR_CODE']
  ): Promise<string | undefined> {
    return new Promise<string | undefined>(async (resolve, reject) => {
      this.source = source;
      this.showButton = showButton;
      
      this.platform.pause.pipe(
        take(1)
      ).subscribe(() => this.stopScanner());
      this.generateImpressionTelemetry(source);
      this.generateStartEvent(source);
      if (this.platform.is("ios")) {
        resolve(this.startQRScanner(screenTitle, displayText, displayTextColor, buttonText, showButton, source));
      } else {
        const permissionStatus = await this.commonUtilService.getGivenPermissionStatus(AndroidPermission.CAMERA);
        if (permissionStatus.hasPermission) {
          resolve(this.startQRScanner(screenTitle, displayText, displayTextColor, buttonText, showButton, source));
        } else if (permissionStatus.isPermissionAlwaysDenied) {
          await this.commonUtilService.showSettingsPageToast('CAMERA_PERMISSION_DESCRIPTION', this.appName, PageId.QRCodeScanner, false);
        } else {
          this.showPopover(source).then((result) => {
            if (result) {
              resolve(result);
            } else {
              resolve(undefined);
            }
          });
        }
      }
    });
  }

  private async showPopover(pageId: string): Promise<string | undefined> {
    return new Promise<string | undefined>(async (resolve, reject) => {
      const confirm = await this.commonUtilService.buildPermissionPopover(
        async (whichBtnClicked: string) => {
          if (whichBtnClicked === this.commonUtilService.translateMessage('NOT_NOW')) {
            this.telemetryGeneratorService.generateInteractTelemetry(
                InteractType.TOUCH,
                InteractSubtype.NOT_NOW_CLICKED,
                pageId === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
                PageId.PERMISSION_POPUP);
            await this.commonUtilService.showSettingsPageToast
            ('CAMERA_PERMISSION_DESCRIPTION', this.appName, PageId.QRCodeScanner, this.appGlobalService.isOnBoardingCompleted);
          } else {
            this.telemetryGeneratorService.generateInteractTelemetry(
                InteractType.TOUCH,
                InteractSubtype.ALLOW_CLICKED,
                pageId === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
                PageId.PERMISSION_POPUP);
            this.appGlobalService.setIsPermissionAsked(PermissionAskedEnum.isCameraAsked, true);
            this.appGlobalService.isNativePopupVisible = true;
            this.permission.requestPermissions([AndroidPermission.CAMERA]).subscribe((status: AndroidPermissionsStatus) => {
              if (status && status.hasPermission) {
                  this.telemetryGeneratorService.generateInteractTelemetry(
                      InteractType.TOUCH,
                      InteractSubtype.ALLOW_CLICKED,
                      pageId === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
                      PageId.APP_PERMISSION_POPUP
                  );
                  this.startScanner(this.source, this.showButton).then((result) => {
                    if (result) {
                      resolve(result);
                    } else {
                      resolve(undefined);
                    }
                    this.appGlobalService.isNativePopupVisible = false;
                  });
              } else {
                  this.telemetryGeneratorService.generateInteractTelemetry(
                      InteractType.TOUCH,
                      InteractSubtype.DENY_CLICKED,
                      pageId === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
                      PageId.APP_PERMISSION_POPUP
                  );
                  this.commonUtilService.showSettingsPageToast
                ('CAMERA_PERMISSION_DESCRIPTION', this.appName, PageId.QRCodeScanner, this.appGlobalService.isOnBoardingCompleted);
                  this.appGlobalService.setNativePopupVisible(false, 1000);
              }
            }, (e) => { reject(e); });
          }
        }, this.appName, this.commonUtilService.translateMessage('CAMERA'), 'CAMERA_PERMISSION_DESCRIPTION', PageId.QRCodeScanner,
          this.appGlobalService.isOnBoardingCompleted
      );

      await confirm.present();
    });
  }

  public stopScanner() {
    if (!this.isScannerActive) {
      return;
    }
    if (this.platform.is("ios") && this.qrModal) this.qrModal.dismiss();
    // to prevent back event propagating up to parent
    setTimeout(() => {
      (window as any).qrScanner.stopScanner();
      this.isScannerActive = false;
    }, 100);
  }

private getProfileSettingConfig() {
    this.profile = this.appGlobalService.getCurrentUser();
    if (this.commonUtilService.isAccessibleForNonStudentRole(this.profile.profileType)) {
      initTabs(this.container, GUEST_TEACHER_TABS);
    } else if (this.profile.profileType === ProfileType.STUDENT) {
      initTabs(this.container, GUEST_STUDENT_TABS);
    }
    this.stopScanner();
    const navigationExtras: NavigationExtras = { state: { loginMode: 'guest' } };
    this.router.navigate(['/tabs'], navigationExtras);
  }

  private async startQRScanner(
    screenTitle: string, displayText: string, displayTextColor: string,
    buttonText: string, showButton: boolean, source: string): Promise<string | undefined> {

    if (this.isScannerActive) {
      return;
    }
    this.isScannerActive = true;
    if (this.platform.is("ios")) {
      this.qrModal = await this.modalCtrl.create({
        component: QrScannerIOSComponent,
        cssClass: 'qr-scanner-modal',
        showBackdrop: false,
        backdropDismiss: true,
        mode: 'ios',
        swipeToClose: false
      })
      await this.qrModal.present();
      this.qrModal.onWillDismiss().finally(() => {
        this.stopScanner();
      });
    }
    
    return new Promise<string | undefined>((resolve, reject) => {
      (window as any).qrScanner.startScanner(screenTitle, displayText,
        displayTextColor, buttonText, showButton, this.platform.isRTL, async (scannedData) => {
          if (scannedData === 'skip') {
            this.stopScanner();
            this.telemetryGeneratorService.generateInteractTelemetry(
              InteractType.TOUCH,
              InteractSubtype.NO_QR_CODE_CLICKED,
              Environment.ONBOARDING,
              PageId.QRCodeScanner);
            this.generateEndEvent(source, '');
          } else {
            const dialCode = await this.qrScannerResultHandler.parseDialCode(scannedData);
            if (scannedData === 'cancel' ||
              scannedData === 'cancel_hw_back' ||
              scannedData === 'cancel_nav_back') {
              this.telemetryGeneratorService.generateBackClickedTelemetry(PageId.SCAN,
                source === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
                scannedData === 'cancel_nav_back');
              this.telemetryGeneratorService.generateBackClickedNewTelemetry(
                scannedData === 'cancel_hw_back',
                this.appGlobalService.isOnBoardingCompleted ? Environment.HOME : Environment.ONBOARDING,
                PageId.SCAN
               );
              this.telemetryGeneratorService.generateInteractTelemetry(
                InteractType.OTHER,
                InteractSubtype.QRCodeScanCancelled,
                Environment.HOME,
                PageId.QRCodeScanner);
              this.generateEndEvent(source, '');
            } else if (dialCode) {
              const corRelationList: Array<CorrelationData> = [];
              corRelationList.push({id: dialCode, type: CorReleationDataType.QR});
              this.telemetryGeneratorService.generateInteractTelemetry(
                InteractType.QR_CAPTURED,
                '',
                source === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
                PageId.SCAN,
                undefined,
                undefined,
                undefined,
                corRelationList);
              this.generateImpressionTelemetry(source, dialCode);
              this.qrScannerResultHandler.handleDialCode(source, scannedData, dialCode);

            } else if (this.qrScannerResultHandler.isContentId(scannedData)) {
              this.qrScannerResultHandler.handleContentId(source, scannedData);
            } else if(scannedData.includes('ProjectCertificate')) {
              this.projectCert.getProjectCertificate(scannedData);
            } else if(scannedData.includes('data=') || scannedData.includes('t=URL')) {
              this.qrScannerResultHandler.handleRcCertsQR(scannedData);
            } else if (scannedData.includes('/certs/')) {
              this.qrScannerResultHandler.handleCertsQR(source, scannedData);
            } else if(scannedData.includes('/manage-learn/')) {
              this.qrScannerResultHandler.manageLearScan(scannedData);
            } else {
              this.qrScannerResultHandler.handleInvalidQRCode(source, scannedData);
              this.showInvalidCodeAlert(scannedData);
            }
            this.stopScanner();
          }
          resolve(scannedData);
        }, (e) => {
          reject(e);
          if (this.platform.is("ios") && ["camera_access_denied", "camera_access_restricted"].includes(e)) {
            this.commonUtilService.showSettingsPageToast('CAMERA_PERMISSION_DESCRIPTION', this.appName, PageId.QRCodeScanner, false)
          }
          this.stopScanner();
        });
    });
  }

private generateImpressionTelemetry(source, dialCode?) {
    if (dialCode) {
     const corRelationList: Array<CorrelationData> = [];
     corRelationList.push({id: dialCode, type: CorReleationDataType.QR});
     this.telemetryGeneratorService.generateImpressionTelemetry(
      ImpressionType.QR_REQUEST, '',
      PageId.SCAN,
      source ? Environment.ONBOARDING : Environment.HOME, '', '', '',
      undefined,
      corRelationList);
     } else {
      this.telemetryGeneratorService.generatePageLoadedTelemetry(
        PageId.SCAN,
        source === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME
     );
      this.telemetryGeneratorService.generateImpressionTelemetry(
        ImpressionType.VIEW,
        ImpressionSubtype.QRCodeScanInitiate,
        source,
        source === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME);
     }
  }

private generateStartEvent(pageId: string) {
    const telemetryObject = new TelemetryObject('', 'qr', undefined);
    this.telemetryGeneratorService.generateStartTelemetry(
      PageId.QRCodeScanner,
      telemetryObject);
  }

private generateEndEvent(pageId: string, qrData: string) {
    if (pageId) {
      const telemetryObject: TelemetryObject = new TelemetryObject(qrData, 'qr', undefined);

      this.telemetryGeneratorService.generateEndTelemetry(
        'qr',
        Mode.PLAY,
        PageId.QRCodeScanner,
        Environment.HOME,
        telemetryObject
      );
    }
  }

  private async showInvalidCodeAlert(scannedData) {
    this.telemetryGeneratorService.generateInteractTelemetry(
      InteractType.OTHER,
      InteractSubtype.QR_CODE_INVALID,
      this.source === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
      this.source
    );
    if (this.source !== 'permission') {
      const corRelationList: CorrelationData[] = [{
        id: PageId.SCAN,
        type: CorReleationDataType.CHILD_UI
      }];
      this.telemetryGeneratorService.generateImpressionTelemetry(
          InteractSubtype.QR_CODE_INVALID, '',
          this.source === PageId.ONBOARDING_PROFILE_PREFERENCES ? PageId.SCAN_OR_MANUAL : this.source,
          this.source === PageId.ONBOARDING_PROFILE_PREFERENCES ? Environment.ONBOARDING : Environment.HOME,
          undefined,
          undefined,
          undefined,
          undefined,
          corRelationList
      );
      this.commonUtilService.afterOnBoardQRErrorAlert('INVALID_QR', 'UNKNOWN_QR', this.source, scannedData);
      return;
    }
  }
}
export interface QRResultCallback {
  dialcode(scanResult: string, code: string);

  content(scanResult: string, contentId: string);
}

results matching ""

    No results matching ""