diff --git a/src/core/core.module.ts b/src/core/core.module.ts index 44ca6128ecd..71f61630462 100644 --- a/src/core/core.module.ts +++ b/src/core/core.module.ts @@ -50,6 +50,7 @@ import { CoreUpdateManagerProvider } from '@services/update-manager'; import { CoreUrlUtilsProvider } from '@services/utils/url'; import { CoreUtilsProvider } from '@services/utils/utils'; import { CoreWSProvider } from '@services/ws'; +import { CoreQRScannerService } from '@services/qrscanner'; export const CORE_SERVICES: Type[] = [ CoreAppProvider, @@ -87,6 +88,7 @@ export const CORE_SERVICES: Type[] = [ HammerModule, ], providers: [ + CoreQRScannerService, { provide: HTTP_INTERCEPTORS, useClass: CoreInterceptor, multi: true }, { provide: HAMMER_GESTURE_CONFIG, useClass: CoreHammerGestureConfig }, { provide: ApplicationInitStatus, useClass: CoreApplicationInitStatus, deps: [Injector] }, diff --git a/src/core/features/native/native.module.ts b/src/core/features/native/native.module.ts index ae1248de577..532dd957d62 100644 --- a/src/core/features/native/native.module.ts +++ b/src/core/features/native/native.module.ts @@ -31,7 +31,6 @@ import { Keyboard } from '@ionic-native/keyboard/ngx'; import { LocalNotifications } from '@ionic-native/local-notifications/ngx'; import { MediaCapture } from '@ionic-native/media-capture/ngx'; import { Push } from '@moodlehq/ionic-native-push/ngx'; -import { QRScanner } from '@ionic-native/qr-scanner/ngx'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { SQLite } from '@ionic-native/sqlite/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; @@ -55,7 +54,6 @@ export const CORE_NATIVE_SERVICES = [ LocalNotifications, MediaCapture, Push, - QRScanner, SplashScreen, StatusBar, SQLite, @@ -82,7 +80,6 @@ export const CORE_NATIVE_SERVICES = [ LocalNotifications, MediaCapture, Push, - QRScanner, SplashScreen, SQLite, StatusBar, diff --git a/src/core/services/qrscanner.ts b/src/core/services/qrscanner.ts new file mode 100644 index 00000000000..05bb3ff29d5 --- /dev/null +++ b/src/core/services/qrscanner.ts @@ -0,0 +1,93 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { makeSingleton } from '@singletons'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +export class CoreQRScannerService { + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private window: any; + + constructor() { + this.window = window; + } + + /** + * Destroy QR scanner instance. + * + * @returns null + */ + destroy(): Promise { + return new Promise((resolve) => this.window.QRScanner.destroy(resolve)); + } + + /** + * Prepare QR scanner instance. + * + * @returns qr scanner status. + */ + prepare(): Promise { + return new Promise(resolve => + this.window.QRScanner.prepare((foo: unknown, status: CoreQRScannerStatus) => (resolve(status)))); + } + + /** + * Show QR Scanner. + * + * @returns Qr scanner status. + */ + show(): Promise { + return new Promise(resolve => this.window.QRScanner.show((status: CoreQRScannerStatus) => resolve(status))); + } + + /** + * Return QR content scanned. + * + * @returns Content scanned. + */ + scan(): Observable { + const subject = new BehaviorSubject(''); + this.window.QRScanner.scan((foo: unknown, text: string) => subject.next(text)); + + return subject.asObservable().pipe(filter(text => !!text)); + } + + /** + * Hide QR Scanner. + * + * @returns null. + */ + hide(): Promise { + return new Promise((resolve) => this.window.QRScanner.hide(resolve)); + } + +} + +export const CoreQRScanner = makeSingleton(CoreQRScannerService); + +export type CoreQRScannerStatus = { + authorized: boolean; + denied: boolean; + restricted: boolean; + prepared: boolean; + scanning: boolean; + previewing: boolean; + showing: boolean; + lightEnabled: boolean; + canOpenSettings: boolean; + canEnableLight: boolean; + canChangeCamera: boolean; + currentCamera: number; +}; diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index 16ccfe1f2ce..7ba92369632 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -24,7 +24,7 @@ import { CoreWS } from '@services/ws'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreTextUtils } from '@services/utils/text'; -import { makeSingleton, Clipboard, InAppBrowser, FileOpener, WebIntent, QRScanner, Translate, NgZone } from '@singletons'; +import { makeSingleton, Clipboard, InAppBrowser, FileOpener, WebIntent, Translate, NgZone } from '@singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreViewerQRScannerComponent } from '@features/viewer/components/qr-scanner/qr-scanner'; import { CoreCanceledError } from '@classes/errors/cancelederror'; @@ -40,6 +40,7 @@ import { CoreSites } from '@services/sites'; import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreUrlUtils } from './url'; +import { CoreQRScanner } from '@services/qrscanner'; export type TreeNode = T & { children: TreeNode[] }; @@ -1707,7 +1708,7 @@ export class CoreUtilsProvider { // Ask the user for permission to use the camera. // The scan method also does this, but since it returns an Observable we wouldn't be able to detect if the user denied. try { - const status = await QRScanner.prepare(); + const status = await CoreQRScanner.prepare(); if (!status.authorized) { // No access to the camera, reject. In android this shouldn't happen, denying access passes through catch. @@ -1724,12 +1725,12 @@ export class CoreUtilsProvider { deferred: new CorePromisedValue(), // When text is received, stop scanning and return the text. - observable: QRScanner.scan().subscribe(text => this.stopScanQR(text, false)), + observable: CoreQRScanner.scan().subscribe(text => this.stopScanQR(text, false)), }; // Show the camera. try { - await QRScanner.show(); + await CoreQRScanner.show(); document.body.classList.add('core-scanning-qr'); @@ -1772,8 +1773,8 @@ export class CoreUtilsProvider { // Set color-scheme to the initial value. document.querySelector('meta[name="color-scheme"]')?.setAttribute('content', this.initialColorSchemeContent); - QRScanner.hide(); - QRScanner.destroy(); + CoreQRScanner.hide(); + CoreQRScanner.destroy(); this.qrScanData.observable.unsubscribe(); // Stop scanning. diff --git a/src/core/singletons/index.ts b/src/core/singletons/index.ts index 493dd35a012..1cf87b2d903 100644 --- a/src/core/singletons/index.ts +++ b/src/core/singletons/index.ts @@ -54,7 +54,6 @@ import { Keyboard as KeyboardService } from '@ionic-native/keyboard/ngx'; import { LocalNotifications as LocalNotificationsService } from '@ionic-native/local-notifications/ngx'; import { MediaCapture as MediaCaptureService } from '@ionic-native/media-capture/ngx'; import { Push as PushService } from '@moodlehq/ionic-native-push/ngx'; -import { QRScanner as QRScannerService } from '@ionic-native/qr-scanner/ngx'; import { StatusBar as StatusBarService } from '@ionic-native/status-bar/ngx'; import { SplashScreen as SplashScreenService } from '@ionic-native/splash-screen/ngx'; import { SQLite as SQLiteService } from '@ionic-native/sqlite/ngx'; @@ -188,7 +187,6 @@ export const LocalNotifications = makeSingleton(LocalNotificationsService); export const MediaCapture = makeSingleton(MediaCaptureService); export const NativeHttp = makeSingleton(HTTP); export const Push = makeSingleton(PushService); -export const QRScanner = makeSingleton(QRScannerService); export const StatusBar = makeSingleton(StatusBarService); export const SplashScreen = makeSingleton(SplashScreenService); export const SQLite = makeSingleton(SQLiteService);