2020-10-06 08:48:26 +00:00
|
|
|
// (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.
|
|
|
|
|
2020-12-07 13:31:40 +00:00
|
|
|
import { ApplicationRef, ApplicationInitStatus, Injector, NgZone as NgZoneService, Type } from '@angular/core';
|
2021-01-14 11:58:51 +00:00
|
|
|
import { Router as RouterService } from '@angular/router';
|
2020-10-07 08:52:51 +00:00
|
|
|
import { HttpClient } from '@angular/common/http';
|
2020-10-06 08:48:26 +00:00
|
|
|
|
2020-10-14 06:34:28 +00:00
|
|
|
import {
|
|
|
|
Platform as PlatformService,
|
|
|
|
AlertController as AlertControllerService,
|
|
|
|
LoadingController as LoadingControllerService,
|
|
|
|
ModalController as ModalControllerService,
|
|
|
|
ToastController as ToastControllerService,
|
2020-10-15 15:06:50 +00:00
|
|
|
GestureController as GestureControllerService,
|
2020-11-06 14:34:01 +00:00
|
|
|
ActionSheetController as ActionSheetControllerService,
|
2021-01-14 11:58:51 +00:00
|
|
|
NavController as NavControllerService,
|
2021-02-04 14:13:59 +00:00
|
|
|
PopoverController as PopoverControllerService,
|
2020-10-14 06:34:28 +00:00
|
|
|
} from '@ionic/angular';
|
2020-10-07 08:52:51 +00:00
|
|
|
|
2020-12-17 14:37:25 +00:00
|
|
|
import { Badge as BadgeService } from '@ionic-native/badge/ngx';
|
2020-11-06 14:34:01 +00:00
|
|
|
import { Camera as CameraService } from '@ionic-native/camera/ngx';
|
|
|
|
import { Chooser as ChooserService } from '@ionic-native/chooser/ngx';
|
2020-10-07 08:52:51 +00:00
|
|
|
import { Clipboard as ClipboardService } from '@ionic-native/clipboard/ngx';
|
|
|
|
import { Diagnostic as DiagnosticService } from '@ionic-native/diagnostic/ngx';
|
|
|
|
import { Device as DeviceService } from '@ionic-native/device/ngx';
|
|
|
|
import { File as FileService } from '@ionic-native/file/ngx';
|
|
|
|
import { FileOpener as FileOpenerService } from '@ionic-native/file-opener/ngx';
|
|
|
|
import { FileTransfer as FileTransferService } from '@ionic-native/file-transfer/ngx';
|
|
|
|
import { Geolocation as GeolocationService } from '@ionic-native/geolocation/ngx';
|
2020-10-14 06:34:28 +00:00
|
|
|
import { HTTP } from '@ionic-native/http/ngx';
|
2020-10-07 08:52:51 +00:00
|
|
|
import { InAppBrowser as InAppBrowserService } from '@ionic-native/in-app-browser/ngx';
|
2020-10-14 06:34:28 +00:00
|
|
|
import { WebView as WebViewService } from '@ionic-native/ionic-webview/ngx';
|
2020-10-07 08:52:51 +00:00
|
|
|
import { Keyboard as KeyboardService } from '@ionic-native/keyboard/ngx';
|
|
|
|
import { LocalNotifications as LocalNotificationsService } from '@ionic-native/local-notifications/ngx';
|
2020-11-06 14:34:01 +00:00
|
|
|
import { Media as MediaService } from '@ionic-native/media/ngx';
|
|
|
|
import { MediaCapture as MediaCaptureService } from '@ionic-native/media-capture/ngx';
|
2020-10-07 08:52:51 +00:00
|
|
|
import { Network as NetworkService } from '@ionic-native/network/ngx';
|
|
|
|
import { Push as PushService } from '@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';
|
|
|
|
import { WebIntent as WebIntentService } from '@ionic-native/web-intent/ngx';
|
|
|
|
import { Zip as ZipService } from '@ionic-native/zip/ngx';
|
|
|
|
|
|
|
|
import { TranslateService } from '@ngx-translate/core';
|
2020-10-06 08:48:26 +00:00
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
const OBJECT_PROTOTYPE = Object.getPrototypeOf(Object);
|
|
|
|
|
2020-12-07 13:31:40 +00:00
|
|
|
/**
|
|
|
|
* Injector instance used to resolve singletons.
|
|
|
|
*/
|
|
|
|
let singletonsInjector: Injector | null = null;
|
2020-10-06 08:48:26 +00:00
|
|
|
|
2020-12-07 13:31:40 +00:00
|
|
|
/**
|
2021-03-02 09:51:23 +00:00
|
|
|
* Helper to get service class methods.
|
2020-12-07 13:31:40 +00:00
|
|
|
*/
|
2021-03-02 09:51:23 +00:00
|
|
|
type GetMethods<T> = {
|
|
|
|
[K in keyof T]: T[K] extends (...args: unknown[]) => unknown ? K : never;
|
|
|
|
}[keyof T];
|
2020-12-07 13:31:40 +00:00
|
|
|
|
|
|
|
/**
|
2021-03-02 09:51:23 +00:00
|
|
|
* Singleton proxy created using the factory method.
|
|
|
|
*
|
|
|
|
* @see makeSingleton
|
2020-12-07 13:31:40 +00:00
|
|
|
*/
|
2021-03-02 09:51:23 +00:00
|
|
|
export type CoreSingletonProxy<Service, Getters extends keyof Service = never> =
|
|
|
|
Pick<Service, GetMethods<Service>> &
|
|
|
|
Pick<Service, Getters> &
|
|
|
|
{
|
|
|
|
instance: Service;
|
|
|
|
setInstance(instance: Service): void;
|
|
|
|
};
|
2020-10-06 08:48:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the injector that will be used to resolve instances in the singletons of this module.
|
|
|
|
*
|
|
|
|
* @param injector Module injector.
|
|
|
|
*/
|
|
|
|
export function setSingletonsInjector(injector: Injector): void {
|
2020-12-07 13:31:40 +00:00
|
|
|
singletonsInjector = injector;
|
2020-10-06 08:48:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-02 09:51:23 +00:00
|
|
|
* Make a singleton proxy for the given injection token.
|
|
|
|
*
|
|
|
|
* This method will return an object that will proxy method calls to an underlying service instance. Getters will also be proxied,
|
|
|
|
* but these need to be configured manually using the `getters` argument. Most of the time, this proxy can be used directly like
|
|
|
|
* you would use a service instance. If you need to get the real service instance, it can be accessed through the `instance`
|
|
|
|
* property and it can be set with the `setInstance` method.
|
2020-10-06 08:48:26 +00:00
|
|
|
*
|
2021-03-02 09:51:23 +00:00
|
|
|
* @param injectionToken Injection token used to resolve the service. This is usually the service class if the provider was
|
|
|
|
* defined using a class or the string used in the `provide` key if it was defined using an object.
|
|
|
|
* @param getters Getter names to proxy.
|
|
|
|
* @return Singleton proxy.
|
2020-10-06 08:48:26 +00:00
|
|
|
*/
|
2021-03-02 09:51:23 +00:00
|
|
|
export function makeSingleton<Service>(injectionToken: Type<Service> | Type<unknown> | string): CoreSingletonProxy<Service, never>;
|
|
|
|
export function makeSingleton<Service, Getters extends keyof Service>(
|
|
|
|
injectionToken: Type<Service> | Type<unknown> | string,
|
|
|
|
getters: Getters[],
|
|
|
|
): CoreSingletonProxy<Service, Getters>;
|
|
|
|
export function makeSingleton<Service, Getters extends keyof Service>(
|
|
|
|
injectionToken: Type<Service> | Type<unknown> | string,
|
|
|
|
getters: Getters[] = [],
|
|
|
|
): CoreSingletonProxy<Service, Getters> {
|
|
|
|
// Define instance manipulation affordances.
|
|
|
|
const proxy = {
|
|
|
|
setInstance(instance: Service) {
|
|
|
|
Object.defineProperty(proxy, 'instance', {
|
|
|
|
value: instance,
|
|
|
|
configurable: true,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
} as CoreSingletonProxy<Service, Getters>;
|
|
|
|
|
|
|
|
Object.defineProperty(proxy, 'instance', {
|
|
|
|
get: () => {
|
|
|
|
if (!singletonsInjector) {
|
|
|
|
throw new Error('Can\'t resolve a singleton instance without an injector');
|
|
|
|
}
|
|
|
|
|
|
|
|
const instance = singletonsInjector.get(injectionToken);
|
|
|
|
|
|
|
|
proxy.setInstance(instance);
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
},
|
|
|
|
configurable: true,
|
|
|
|
});
|
2020-12-07 13:31:40 +00:00
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
// Define method and getter proxies.
|
|
|
|
if (isServiceClass(injectionToken)) {
|
|
|
|
// Get property descriptors, going all the way up the prototype chain (for services extending other classes).
|
|
|
|
let parentPrototype = injectionToken;
|
|
|
|
let descriptors: Record<string, PropertyDescriptor> = {};
|
2020-12-07 13:31:40 +00:00
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
do {
|
|
|
|
descriptors = {
|
|
|
|
...Object.getOwnPropertyDescriptors(parentPrototype.prototype),
|
|
|
|
...descriptors,
|
|
|
|
};
|
2020-12-07 13:31:40 +00:00
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
parentPrototype = Object.getPrototypeOf(parentPrototype);
|
|
|
|
} while (parentPrototype !== OBJECT_PROTOTYPE);
|
|
|
|
|
|
|
|
// Don't proxy constructor calls.
|
|
|
|
delete descriptors['constructor'];
|
|
|
|
|
|
|
|
// Define method proxies.
|
|
|
|
for (const [property, descriptor] of Object.entries(descriptors)) {
|
|
|
|
// Skip getters and setters.
|
|
|
|
if (descriptor.get || descriptor.set) {
|
|
|
|
continue;
|
2020-12-07 13:31:40 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
// Define method proxy.
|
|
|
|
Object.defineProperty(proxy, property, {
|
|
|
|
value: (...args) => proxy.instance[property].call(proxy.instance, ...args),
|
|
|
|
configurable: true,
|
|
|
|
});
|
2020-12-07 13:31:40 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
// Define getter proxies.
|
|
|
|
for (const getter of getters) {
|
|
|
|
Object.defineProperty(proxy, getter, { get: () => proxy.instance[getter] });
|
2020-12-07 13:31:40 +00:00
|
|
|
}
|
2021-03-02 09:51:23 +00:00
|
|
|
}
|
2020-12-07 13:31:40 +00:00
|
|
|
|
2021-03-02 09:51:23 +00:00
|
|
|
return proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Type guard to check if an injection token is a service class.
|
|
|
|
*
|
|
|
|
* @param injectionToken Injection token.
|
|
|
|
* @return Whether the token is a class.
|
|
|
|
*/
|
|
|
|
function isServiceClass(injectionToken: Type<unknown> | string): injectionToken is Type<unknown> {
|
|
|
|
return typeof injectionToken !== 'string';
|
2020-10-06 08:48:26 +00:00
|
|
|
}
|
|
|
|
|
2020-10-07 08:52:51 +00:00
|
|
|
// Convert ionic-native services to singleton.
|
2020-12-17 14:37:25 +00:00
|
|
|
export class Badge extends makeSingleton(BadgeService) {}
|
2020-11-06 14:34:01 +00:00
|
|
|
export class Camera extends makeSingleton(CameraService) {}
|
|
|
|
export class Chooser extends makeSingleton(ChooserService) {}
|
2020-10-07 08:52:51 +00:00
|
|
|
export class Clipboard extends makeSingleton(ClipboardService) {}
|
|
|
|
export class Device extends makeSingleton(DeviceService) {}
|
|
|
|
export class Diagnostic extends makeSingleton(DiagnosticService) {}
|
|
|
|
export class File extends makeSingleton(FileService) {}
|
|
|
|
export class FileOpener extends makeSingleton(FileOpenerService) {}
|
|
|
|
export class FileTransfer extends makeSingleton(FileTransferService) {}
|
|
|
|
export class Geolocation extends makeSingleton(GeolocationService) {}
|
|
|
|
export class InAppBrowser extends makeSingleton(InAppBrowserService) {}
|
|
|
|
export class Keyboard extends makeSingleton(KeyboardService) {}
|
|
|
|
export class LocalNotifications extends makeSingleton(LocalNotificationsService) {}
|
2020-11-06 14:34:01 +00:00
|
|
|
export class Media extends makeSingleton(MediaService) {}
|
|
|
|
export class MediaCapture extends makeSingleton(MediaCaptureService) {}
|
2020-10-14 06:34:28 +00:00
|
|
|
export class NativeHttp extends makeSingleton(HTTP) {}
|
2020-10-07 08:52:51 +00:00
|
|
|
export class Network extends makeSingleton(NetworkService) {}
|
|
|
|
export class Push extends makeSingleton(PushService) {}
|
|
|
|
export class QRScanner extends makeSingleton(QRScannerService) {}
|
|
|
|
export class StatusBar extends makeSingleton(StatusBarService) {}
|
|
|
|
export class SplashScreen extends makeSingleton(SplashScreenService) {}
|
|
|
|
export class SQLite extends makeSingleton(SQLiteService) {}
|
|
|
|
export class WebIntent extends makeSingleton(WebIntentService) {}
|
2020-10-14 06:34:28 +00:00
|
|
|
export class WebView extends makeSingleton(WebViewService) {}
|
2020-10-07 08:52:51 +00:00
|
|
|
export class Zip extends makeSingleton(ZipService) {}
|
|
|
|
|
|
|
|
// Convert some Angular and Ionic injectables to singletons.
|
|
|
|
export class NgZone extends makeSingleton(NgZoneService) {}
|
|
|
|
export class Http extends makeSingleton(HttpClient) {}
|
|
|
|
export class Platform extends makeSingleton(PlatformService) {}
|
2020-11-06 14:34:01 +00:00
|
|
|
export class ActionSheetController extends makeSingleton(ActionSheetControllerService) {}
|
2020-10-14 06:34:28 +00:00
|
|
|
export class AlertController extends makeSingleton(AlertControllerService) {}
|
|
|
|
export class LoadingController extends makeSingleton(LoadingControllerService) {}
|
|
|
|
export class ModalController extends makeSingleton(ModalControllerService) {}
|
2021-02-04 14:13:59 +00:00
|
|
|
export class PopoverController extends makeSingleton(PopoverControllerService) {}
|
2020-10-14 06:34:28 +00:00
|
|
|
export class ToastController extends makeSingleton(ToastControllerService) {}
|
2020-10-15 15:06:50 +00:00
|
|
|
export class GestureController extends makeSingleton(GestureControllerService) {}
|
2020-12-01 17:35:07 +00:00
|
|
|
export class ApplicationInit extends makeSingleton(ApplicationInitStatus) {}
|
|
|
|
export class Application extends makeSingleton(ApplicationRef) {}
|
2021-01-14 11:58:51 +00:00
|
|
|
export class NavController extends makeSingleton(NavControllerService) {}
|
|
|
|
export class Router extends makeSingleton(RouterService) {}
|
2020-10-07 08:52:51 +00:00
|
|
|
|
|
|
|
// Convert external libraries injectables.
|
2021-02-16 10:18:12 +00:00
|
|
|
export class Translate extends makeSingleton(TranslateService) {
|
|
|
|
|
|
|
|
static instant(key: string | Array<string>, interpolateParams?: Record<string, unknown>): string | any {
|
|
|
|
return this.instance.instant(key, interpolateParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|