forked from CIT/Vmeda.Online
		
	
						commit
						1c1d1578ff
					
				
							
								
								
									
										15
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -2123,6 +2123,21 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "@ionic-native/badge": {
 | 
			
		||||
      "version": "5.30.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@ionic-native/badge/-/badge-5.30.0.tgz",
 | 
			
		||||
      "integrity": "sha512-9bz8AsdiJVAPEGGRLihoWWkikJf38xjCBgshBpgMxlXGmaDKMQQ2PHl8EeSlzjDCZy3POLbtAQnLTfYp+zqXEg==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@types/cordova": "^0.0.34"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/cordova": {
 | 
			
		||||
          "version": "0.0.34",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
 | 
			
		||||
          "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "@ionic-native/camera": {
 | 
			
		||||
      "version": "5.29.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@ionic-native/camera/-/camera-5.29.0.tgz",
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,7 @@
 | 
			
		||||
    "@angular/platform-browser": "~10.0.0",
 | 
			
		||||
    "@angular/platform-browser-dynamic": "~10.0.0",
 | 
			
		||||
    "@angular/router": "~10.0.0",
 | 
			
		||||
    "@ionic-native/badge": "^5.30.0",
 | 
			
		||||
    "@ionic-native/camera": "^5.29.0",
 | 
			
		||||
    "@ionic-native/chooser": "^5.29.0",
 | 
			
		||||
    "@ionic-native/clipboard": "^5.28.0",
 | 
			
		||||
 | 
			
		||||
@ -21,8 +21,8 @@ import { CoreContentLinksDelegate } from '@features/contentlinks/services/conten
 | 
			
		||||
import { CoreUserDelegate } from '@features/user/services/user-delegate';
 | 
			
		||||
import { AddonBadgesUserHandler } from './services/handlers/user';
 | 
			
		||||
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
 | 
			
		||||
// @todo import { CorePushNotificationsDelegate } from '@core/pushnotifications/services/delegate';
 | 
			
		||||
// import { AddonBadgesPushClickHandler } from './services/push-click-handler';
 | 
			
		||||
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
 | 
			
		||||
import { AddonBadgesPushClickHandler } from './services/handlers/push-click';
 | 
			
		||||
 | 
			
		||||
const mainMenuHomeSiblingRoutes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
@ -44,7 +44,7 @@ const mainMenuHomeSiblingRoutes: Routes = [
 | 
			
		||||
                CoreContentLinksDelegate.instance.registerHandler(AddonBadgesMyBadgesLinkHandler.instance);
 | 
			
		||||
                CoreContentLinksDelegate.instance.registerHandler(AddonBadgesBadgeLinkHandler.instance);
 | 
			
		||||
                CoreUserDelegate.instance.registerHandler(AddonBadgesUserHandler.instance);
 | 
			
		||||
                // CorePushNotificationsDelegate.instance.registerHandler(AddonBadgesPushClickHandler.instance);
 | 
			
		||||
                CorePushNotificationsDelegate.instance.registerClickHandler(AddonBadgesPushClickHandler.instance);
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										79
									
								
								src/addons/badges/services/handlers/push-click.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/addons/badges/services/handlers/push-click.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
 | 
			
		||||
import { AddonBadges } from '../badges';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
 | 
			
		||||
import { CoreNavHelper } from '@services/nav-helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler for badges push notifications clicks.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonBadgesPushClickHandlerService implements CorePushNotificationsClickHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonBadgesPushClickHandler';
 | 
			
		||||
    priority = 200;
 | 
			
		||||
    featureName = 'CoreUserDelegate_AddonBadges';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a notification click is handled by this handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification The notification to check.
 | 
			
		||||
     * @return Whether the notification click is handled by this handler
 | 
			
		||||
     */
 | 
			
		||||
    async handles(notification: CorePushNotificationsNotificationBasicData): Promise<boolean> {
 | 
			
		||||
        const data = notification.customdata || {};
 | 
			
		||||
 | 
			
		||||
        if (CoreUtils.instance.isTrueOrOne(notification.notif) && notification.moodlecomponent == 'moodle' &&
 | 
			
		||||
                (notification.name == 'badgerecipientnotice' || (notification.name == 'badgecreatornotice' && data.hash))) {
 | 
			
		||||
            return AddonBadges.instance.isPluginEnabled(notification.site);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle the notification click.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification The notification to check.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async handleClick(notification: CorePushNotificationsNotificationBasicData): Promise<void> {
 | 
			
		||||
        const data = notification.customdata || {};
 | 
			
		||||
 | 
			
		||||
        if (data.hash) {
 | 
			
		||||
            // We have the hash, open the badge directly.
 | 
			
		||||
            return CoreNavHelper.instance.goInSite('/badges/issue', { courseId: 0, badgeHash: data.hash }, notification.site);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // No hash, open the list of user badges.
 | 
			
		||||
        await CoreUtils.instance.ignoreErrors(
 | 
			
		||||
            AddonBadges.instance.invalidateUserBadges(
 | 
			
		||||
                0,
 | 
			
		||||
                Number(notification.usertoid),
 | 
			
		||||
                notification.site,
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        await CoreNavHelper.instance.goInSite('/badges/user', {}, notification.site);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonBadgesPushClickHandler extends makeSingleton(AddonBadgesPushClickHandlerService) {}
 | 
			
		||||
@ -35,6 +35,7 @@ import {
 | 
			
		||||
} from '../../courses/services/courses';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
			
		||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'mmCourse:';
 | 
			
		||||
 | 
			
		||||
@ -73,7 +74,6 @@ export class CoreCourseProvider {
 | 
			
		||||
        // @todo
 | 
			
		||||
        // protected courseFormatDelegate: CoreCourseFormatDelegate,
 | 
			
		||||
        // protected sitePluginsProvider: CoreSitePluginsProvider,
 | 
			
		||||
        // protected pushNotificationsProvider: CorePushNotificationsProvider,
 | 
			
		||||
        this.logger = CoreLogger.getInstance('CoreCourseProvider');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -857,7 +857,6 @@ export class CoreCourseProvider {
 | 
			
		||||
     * @return Promise resolved when the WS call is successful.
 | 
			
		||||
     * @todo use logHelper. Remove eslint disable when done.
 | 
			
		||||
     */
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
    async logView(courseId: number, sectionNumber?: number, siteId?: string, name?: string): Promise<void> {
 | 
			
		||||
        const params: CoreCourseViewCourseWSParams = {
 | 
			
		||||
            courseid: courseId,
 | 
			
		||||
@ -869,8 +868,7 @@ export class CoreCourseProvider {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.instance.getSite(siteId);
 | 
			
		||||
        // @todo
 | 
			
		||||
        // this.pushNotificationsProvider.logViewEvent(courseId, name, 'course', wsName, { sectionnumber: sectionNumber }, siteId);
 | 
			
		||||
        CorePushNotifications.instance.logViewEvent(courseId, name, 'course', wsName, { sectionnumber: sectionNumber }, siteId);
 | 
			
		||||
        const response: CoreStatusWithWarningsWSResponse = await site.write(wsName, params);
 | 
			
		||||
 | 
			
		||||
        if (!response.status) {
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { CoreEmulatorHelperProvider } from './services/emulator-helper';
 | 
			
		||||
import { CoreEmulatorComponentsModule } from './components/components.module';
 | 
			
		||||
 | 
			
		||||
// Ionic Native services.
 | 
			
		||||
import { Badge } from '@ionic-native/badge/ngx';
 | 
			
		||||
import { Camera } from '@ionic-native/camera/ngx';
 | 
			
		||||
import { Chooser } from '@ionic-native/chooser/ngx';
 | 
			
		||||
import { Clipboard } from '@ionic-native/clipboard/ngx';
 | 
			
		||||
@ -72,6 +73,7 @@ import { ZipMock } from './services/zip';
 | 
			
		||||
        CoreEmulatorComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        Badge,
 | 
			
		||||
        {
 | 
			
		||||
            provide: Camera,
 | 
			
		||||
            deps: [Platform],
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ import { CoreSettingsModule } from './settings/settings.module';
 | 
			
		||||
import { CoreSiteHomeModule } from './sitehome/sitehome.module';
 | 
			
		||||
import { CoreTagModule } from './tag/tag.module';
 | 
			
		||||
import { CoreUserModule } from './user/user.module';
 | 
			
		||||
import { CorePushNotificationsModule } from './pushnotifications/pushnotifications.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
@ -37,6 +38,7 @@ import { CoreUserModule } from './user/user.module';
 | 
			
		||||
        CoreSiteHomeModule,
 | 
			
		||||
        CoreTagModule,
 | 
			
		||||
        CoreUserModule,
 | 
			
		||||
        CorePushNotificationsModule,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class CoreFeaturesModule {}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
// (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 { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { CoreCronDelegate } from '@services/cron';
 | 
			
		||||
import { CorePushNotificationsRegisterCronHandler } from './services/handlers/register-cron';
 | 
			
		||||
import { CorePushNotificationsUnregisterCronHandler } from './services/handlers/unregister-cron';
 | 
			
		||||
import { CorePushNotifications } from './services/pushnotifications';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        {
 | 
			
		||||
            provide: APP_INITIALIZER,
 | 
			
		||||
            multi: true,
 | 
			
		||||
            deps: [],
 | 
			
		||||
            useFactory: () => async () => {
 | 
			
		||||
                // Register the handlers.
 | 
			
		||||
                CoreCronDelegate.instance.register(CorePushNotificationsRegisterCronHandler.instance);
 | 
			
		||||
                CoreCronDelegate.instance.register(CorePushNotificationsUnregisterCronHandler.instance);
 | 
			
		||||
 | 
			
		||||
                await CorePushNotifications.instance.initialize();
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class CorePushNotificationsModule {}
 | 
			
		||||
@ -0,0 +1,143 @@
 | 
			
		||||
// (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 { CoreAppSchema } from '@services/app';
 | 
			
		||||
import { CoreSiteSchema } from '@services/sites';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Database variables for CorePushNotificationsProvider service.
 | 
			
		||||
 * Keep "addon" in some names for backwards compatibility.
 | 
			
		||||
 */
 | 
			
		||||
export const BADGE_TABLE_NAME = 'addon_pushnotifications_badge';
 | 
			
		||||
export const PENDING_UNREGISTER_TABLE_NAME = 'addon_pushnotifications_pending_unregister';
 | 
			
		||||
export const REGISTERED_DEVICES_TABLE_NAME = 'addon_pushnotifications_registered_devices';
 | 
			
		||||
export const APP_SCHEMA: CoreAppSchema = {
 | 
			
		||||
    name: 'CorePushNotificationsProvider',
 | 
			
		||||
    version: 1,
 | 
			
		||||
    tables: [
 | 
			
		||||
        {
 | 
			
		||||
            name: BADGE_TABLE_NAME,
 | 
			
		||||
            columns: [
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'siteid',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'addon',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'number',
 | 
			
		||||
                    type: 'INTEGER',
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
            primaryKeys: ['siteid', 'addon'],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            name: PENDING_UNREGISTER_TABLE_NAME,
 | 
			
		||||
            columns: [
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'siteid',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                    primaryKey: true,
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'siteurl',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'token',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'info',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
};
 | 
			
		||||
export const SITE_SCHEMA: CoreSiteSchema = {
 | 
			
		||||
    name: 'AddonPushNotificationsProvider',
 | 
			
		||||
    version: 1,
 | 
			
		||||
    tables: [
 | 
			
		||||
        {
 | 
			
		||||
            name: REGISTERED_DEVICES_TABLE_NAME,
 | 
			
		||||
            columns: [
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'appid',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'uuid',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'name',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'model',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'platform',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'version',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: 'pushid',
 | 
			
		||||
                    type: 'TEXT',
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
            primaryKeys: ['appid', 'uuid'],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data stored in DB for badge.
 | 
			
		||||
 */
 | 
			
		||||
export type CorePushNotificationsBadgeDBRecord = {
 | 
			
		||||
    siteid: string;
 | 
			
		||||
    addon: string;
 | 
			
		||||
    number: number; // eslint-disable-line id-blacklist
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data stored in DB for pending unregisters.
 | 
			
		||||
 */
 | 
			
		||||
export type CorePushNotificationsPendingUnregisterDBRecord = {
 | 
			
		||||
    siteid: string;
 | 
			
		||||
    siteurl: string;
 | 
			
		||||
    token: string;
 | 
			
		||||
    info: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data stored in DB for registered devices.
 | 
			
		||||
 */
 | 
			
		||||
export type CorePushNotificationsRegisteredDeviceDBRecord = {
 | 
			
		||||
    appid: string; // App ID.
 | 
			
		||||
    uuid: string; // Device UUID.
 | 
			
		||||
    name: string; // Device name.
 | 
			
		||||
    model: string; // Device model.
 | 
			
		||||
    platform: string; // Device platform.
 | 
			
		||||
    version: string; // Device version.
 | 
			
		||||
    pushid: string; // Push ID.
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,75 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { CoreCronHandler } from '@services/cron';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CorePushNotifications } from '../pushnotifications';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cron handler to force a register on a Moodle site when a site is manually synchronized.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class CorePushNotificationsRegisterCronHandlerService implements CoreCronHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'CorePushNotificationsRegisterCronHandler';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether the sync can be executed manually. Call isSync if not defined.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether the sync can be executed manually.
 | 
			
		||||
     */
 | 
			
		||||
    canManualSync(): boolean {
 | 
			
		||||
        return true; // Execute the handler when the site is manually synchronized.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the process.
 | 
			
		||||
     * Receives the ID of the site affected, undefined for all sites.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId ID of the site affected, undefined for all sites.
 | 
			
		||||
     * @return Promise resolved when done, rejected if failure.
 | 
			
		||||
     */
 | 
			
		||||
    async execute(siteId?: string): Promise<void> {
 | 
			
		||||
        if (!siteId || !CorePushNotifications.instance.canRegisterOnMoodle()) {
 | 
			
		||||
            // It's not a specific site, don't do anything.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Register the device again.
 | 
			
		||||
        await CorePushNotifications.instance.registerDeviceOnMoodle(siteId, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the time between consecutive executions.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Time between consecutive executions (in ms).
 | 
			
		||||
     */
 | 
			
		||||
    getInterval(): number {
 | 
			
		||||
        return 86400000; // 1 day. We won't do anything with automatic execution, so use a big number.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether it's a synchronization process or not. True if not defined.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether it's a synchronization process or not.
 | 
			
		||||
     */
 | 
			
		||||
    isSync(): boolean {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CorePushNotificationsRegisterCronHandler extends makeSingleton(CorePushNotificationsRegisterCronHandlerService) {}
 | 
			
		||||
@ -0,0 +1,51 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { CoreCronHandler } from '@services/cron';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CorePushNotifications } from '../pushnotifications';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cron handler to retry pending unregisters.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class CorePushNotificationsUnregisterCronHandlerService implements CoreCronHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'CorePushNotificationsUnregisterCronHandler';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the process.
 | 
			
		||||
     * Receives the ID of the site affected, undefined for all sites.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId ID of the site affected, undefined for all sites.
 | 
			
		||||
     * @return Promise resolved when done, rejected if failure.
 | 
			
		||||
     */
 | 
			
		||||
    async execute(siteId?: string): Promise<void> {
 | 
			
		||||
        await CorePushNotifications.instance.retryUnregisters(siteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the time between consecutive executions.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Time between consecutive executions (in ms).
 | 
			
		||||
     */
 | 
			
		||||
    getInterval(): number {
 | 
			
		||||
        return 300000;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CorePushNotificationsUnregisterCronHandler extends makeSingleton(CorePushNotificationsUnregisterCronHandlerService) {}
 | 
			
		||||
							
								
								
									
										218
									
								
								src/core/features/pushnotifications/services/push-delegate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								src/core/features/pushnotifications/services/push-delegate.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,218 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
import { Subject } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CoreLogger } from '@singletons/logger';
 | 
			
		||||
import { CorePushNotificationsNotificationBasicData } from './pushnotifications';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Interface that all click handlers must implement.
 | 
			
		||||
 */
 | 
			
		||||
export interface CorePushNotificationsClickHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * A name to identify the handler.
 | 
			
		||||
     */
 | 
			
		||||
    name: string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handler's priority. The highest priority is treated first.
 | 
			
		||||
     */
 | 
			
		||||
    priority?: number;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Name of the feature this handler is related to.
 | 
			
		||||
     * It will be used to check if the feature is disabled (@see CoreSite.isFeatureDisabled).
 | 
			
		||||
     */
 | 
			
		||||
    featureName?: string;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a notification click is handled by this handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification The notification to check.
 | 
			
		||||
     * @return Whether the notification click is handled by this handler.
 | 
			
		||||
     */
 | 
			
		||||
    handles(notification: CorePushNotificationsNotificationBasicData): Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle the notification click.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification The notification to check.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    handleClick(notification: CorePushNotificationsNotificationBasicData): Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service to handle push notifications actions to perform when clicked and received.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class CorePushNotificationsDelegateService {
 | 
			
		||||
 | 
			
		||||
    protected logger: CoreLogger;
 | 
			
		||||
    protected observables: { [s: string]: Subject<unknown> } = {};
 | 
			
		||||
    protected clickHandlers: { [s: string]: CorePushNotificationsClickHandler } = {};
 | 
			
		||||
    protected counterHandlers: Record<string, string> = {};
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.logger = CoreLogger.getInstance('CorePushNotificationsDelegate');
 | 
			
		||||
        this.observables['receive'] = new Subject<CorePushNotificationsNotificationBasicData>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Function called when a push notification is clicked. Sends notification to handlers.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification Notification clicked.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async clicked(notification: CorePushNotificationsNotificationBasicData): Promise<void> {
 | 
			
		||||
        if (!notification) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let handlers: CorePushNotificationsClickHandler[] = [];
 | 
			
		||||
 | 
			
		||||
        const promises = Object.values(this.clickHandlers).map(async (handler) => {
 | 
			
		||||
            // Check if the handler is disabled for the site.
 | 
			
		||||
            const disabled = await this.isFeatureDisabled(handler, notification.site);
 | 
			
		||||
 | 
			
		||||
            if (disabled) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Check if the handler handles the notification.
 | 
			
		||||
            const handles = await handler.handles(notification);
 | 
			
		||||
            if (handles) {
 | 
			
		||||
                handlers.push(handler);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        await CoreUtils.instance.ignoreErrors(CoreUtils.instance.allPromises(promises));
 | 
			
		||||
 | 
			
		||||
        // Sort by priority.
 | 
			
		||||
        handlers = handlers.sort((a, b) => (a.priority || 0) <= (b.priority || 0) ? 1 : -1);
 | 
			
		||||
 | 
			
		||||
        // Execute the first one.
 | 
			
		||||
        handlers[0]?.handleClick(notification);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a handler's feature is disabled for a certain site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param handler Handler to check.
 | 
			
		||||
     * @param siteId The site ID to check.
 | 
			
		||||
     * @return Promise resolved with boolean: whether the handler feature is disabled.
 | 
			
		||||
     */
 | 
			
		||||
    protected async isFeatureDisabled(handler: CorePushNotificationsClickHandler, siteId?: string): Promise<boolean> {
 | 
			
		||||
        if (!siteId) {
 | 
			
		||||
            // Notification doesn't belong to a site. Assume all handlers are enabled.
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if (handler.featureName) {
 | 
			
		||||
            // Check if the feature is disabled.
 | 
			
		||||
            return CoreSites.instance.isFeatureDisabled(handler.featureName, siteId);
 | 
			
		||||
        } else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Function called when a push notification is received in foreground (cannot tell when it's received in background).
 | 
			
		||||
     * Sends notification to all handlers.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification Notification received.
 | 
			
		||||
     */
 | 
			
		||||
    received(notification: CorePushNotificationsNotificationBasicData): void {
 | 
			
		||||
        this.observables['receive'].next(notification);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register a push notifications observable for a certain event. Right now, only receive is supported.
 | 
			
		||||
     * let observer = pushNotificationsDelegate.on('receive').subscribe((notification) => {
 | 
			
		||||
     * ...
 | 
			
		||||
     * observer.unsuscribe();
 | 
			
		||||
     *
 | 
			
		||||
     * @param eventName Only receive is permitted.
 | 
			
		||||
     * @return Observer to subscribe.
 | 
			
		||||
     */
 | 
			
		||||
    on<T = unknown>(eventName: string): Subject<T> {
 | 
			
		||||
        if (typeof this.observables[eventName] == 'undefined') {
 | 
			
		||||
            const eventNames = Object.keys(this.observables).join(', ');
 | 
			
		||||
            this.logger.warn(`'${eventName}' event name is not allowed. Use one of the following: '${eventNames}'.`);
 | 
			
		||||
 | 
			
		||||
            return new Subject<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return <Subject<T>> this.observables[eventName];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register a click handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @param handler The handler to register.
 | 
			
		||||
     * @return True if registered successfully, false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    registerClickHandler(handler: CorePushNotificationsClickHandler): boolean {
 | 
			
		||||
        if (typeof this.clickHandlers[handler.name] !== 'undefined') {
 | 
			
		||||
            this.logger.log(`Addon '${handler.name}' already registered`);
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.logger.log(`Registered addon '${handler.name}'`);
 | 
			
		||||
        this.clickHandlers[handler.name] = handler;
 | 
			
		||||
        handler.priority = handler.priority || 0;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register a push notifications handler for update badge counter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name Handler's name.
 | 
			
		||||
     */
 | 
			
		||||
    registerCounterHandler(name: string): void {
 | 
			
		||||
        if (typeof this.counterHandlers[name] == 'undefined') {
 | 
			
		||||
            this.logger.debug(`Registered handler '${name}' as badge counter handler.`);
 | 
			
		||||
            this.counterHandlers[name] = name;
 | 
			
		||||
        } else {
 | 
			
		||||
            this.logger.log(`Handler '${name}' as badge counter handler already registered.`);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a counter handler is present.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name Handler's name.
 | 
			
		||||
     * @return If handler name is present.
 | 
			
		||||
     */
 | 
			
		||||
    isCounterHandlerRegistered(name: string): boolean {
 | 
			
		||||
        return typeof this.counterHandlers[name] != 'undefined';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get all counter badge handlers.
 | 
			
		||||
     *
 | 
			
		||||
     * @return with all the handler names.
 | 
			
		||||
     */
 | 
			
		||||
    getCounterHandlers(): Record<string, string> {
 | 
			
		||||
        return this.counterHandlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CorePushNotificationsDelegate extends makeSingleton(CorePushNotificationsDelegateService) {}
 | 
			
		||||
@ -0,0 +1,910 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
import { ILocalNotification } from '@ionic-native/local-notifications';
 | 
			
		||||
import { NotificationEventResponse, PushOptions, RegistrationEventResponse } from '@ionic-native/push/ngx';
 | 
			
		||||
 | 
			
		||||
import { CoreApp } from '@services/app';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CorePushNotificationsDelegate } from './push-delegate';
 | 
			
		||||
import { CoreLocalNotifications } from '@services/local-notifications';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreConfig } from '@services/config';
 | 
			
		||||
import { CoreConstants } from '@/core/constants';
 | 
			
		||||
import { SQLiteDB } from '@classes/sqlitedb';
 | 
			
		||||
import { CoreSite, CoreSiteInfo } from '@classes/site';
 | 
			
		||||
import { makeSingleton, Badge, Push, Device, Translate, Platform, ApplicationInit, NgZone } from '@singletons';
 | 
			
		||||
import { CoreLogger } from '@singletons/logger';
 | 
			
		||||
import { CoreEvents } from '@singletons/events';
 | 
			
		||||
import {
 | 
			
		||||
    APP_SCHEMA,
 | 
			
		||||
    BADGE_TABLE_NAME,
 | 
			
		||||
    PENDING_UNREGISTER_TABLE_NAME,
 | 
			
		||||
    REGISTERED_DEVICES_TABLE_NAME,
 | 
			
		||||
    CorePushNotificationsPendingUnregisterDBRecord,
 | 
			
		||||
    CorePushNotificationsRegisteredDeviceDBRecord,
 | 
			
		||||
    CorePushNotificationsBadgeDBRecord,
 | 
			
		||||
} from './database/pushnotifications';
 | 
			
		||||
import { CoreError } from '@classes/errors/error';
 | 
			
		||||
import { CoreWSExternalWarning } from '@services/ws';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service to handle push notifications.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class CorePushNotificationsProvider {
 | 
			
		||||
 | 
			
		||||
    static readonly COMPONENT = 'CorePushNotificationsProvider';
 | 
			
		||||
 | 
			
		||||
    protected logger: CoreLogger;
 | 
			
		||||
    protected pushID?: string;
 | 
			
		||||
 | 
			
		||||
    // Variables for DB.
 | 
			
		||||
    protected appDB: Promise<SQLiteDB>;
 | 
			
		||||
    protected resolveAppDB!: (appDB: SQLiteDB) => void;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.appDB = new Promise(resolve => this.resolveAppDB = resolve);
 | 
			
		||||
        this.logger = CoreLogger.getInstance('CorePushNotificationsProvider');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the service.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async initialize(): Promise<void> {
 | 
			
		||||
        await Promise.all([
 | 
			
		||||
            this.initializeDatabase(),
 | 
			
		||||
            this.initializeDefaultChannel(),
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        // Now register the device to receive push notifications. Don't block for this.
 | 
			
		||||
        this.registerDevice();
 | 
			
		||||
 | 
			
		||||
        CoreEvents.on(CoreEvents.NOTIFICATION_SOUND_CHANGED, () => {
 | 
			
		||||
            // Notification sound has changed, register the device again to update the sound setting.
 | 
			
		||||
            this.registerDevice();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Register device on Moodle site when login.
 | 
			
		||||
        CoreEvents.on(CoreEvents.LOGIN, async () => {
 | 
			
		||||
            try {
 | 
			
		||||
                await this.registerDeviceOnMoodle();
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                this.logger.warn('Can\'t register device', error);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        CoreEvents.on(CoreEvents.SITE_DELETED, async (site: CoreSite) => {
 | 
			
		||||
            try {
 | 
			
		||||
                await Promise.all([
 | 
			
		||||
                    this.unregisterDeviceOnMoodle(site),
 | 
			
		||||
                    this.cleanSiteCounters(site.getId()),
 | 
			
		||||
                ]);
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                this.logger.warn('Can\'t unregister device', error);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Listen for local notification clicks (generated by the app).
 | 
			
		||||
        CoreLocalNotifications.instance.registerClick<CorePushNotificationsNotificationBasicData>(
 | 
			
		||||
            CorePushNotificationsProvider.COMPONENT,
 | 
			
		||||
            (notification) => {
 | 
			
		||||
                // Log notification open event.
 | 
			
		||||
                this.logEvent('moodle_notification_open', notification, true);
 | 
			
		||||
 | 
			
		||||
                this.notificationClicked(notification);
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Listen for local notification dismissed events.
 | 
			
		||||
        CoreLocalNotifications.instance.registerObserver<CorePushNotificationsNotificationBasicData>(
 | 
			
		||||
            'clear',
 | 
			
		||||
            CorePushNotificationsProvider.COMPONENT,
 | 
			
		||||
            (notification) => {
 | 
			
		||||
                // Log notification dismissed event.
 | 
			
		||||
                this.logEvent('moodle_notification_dismiss', notification, true);
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the default channel for Android.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async initializeDefaultChannel(): Promise<void> {
 | 
			
		||||
        await Platform.instance.ready();
 | 
			
		||||
 | 
			
		||||
        // Create the default channel.
 | 
			
		||||
        this.createDefaultChannel();
 | 
			
		||||
 | 
			
		||||
        Translate.instance.onLangChange.subscribe(() => {
 | 
			
		||||
            // Update the channel name.
 | 
			
		||||
            this.createDefaultChannel();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize database.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async initializeDatabase(): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreApp.instance.createTablesFromSchema(APP_SCHEMA);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.resolveAppDB(CoreApp.instance.getDB());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check whether the device can be registered in Moodle to receive push notifications.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether the device can be registered in Moodle.
 | 
			
		||||
     */
 | 
			
		||||
    canRegisterOnMoodle(): boolean {
 | 
			
		||||
        return !!this.pushID && CoreApp.instance.isMobile();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete all badge records for a given site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID.
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async cleanSiteCounters(siteId: string): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            const db = await this.appDB;
 | 
			
		||||
            await db.deleteRecords(BADGE_TABLE_NAME, { siteid: siteId } );
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.updateAppCounter();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create the default push channel. It is used to change the name.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async createDefaultChannel(): Promise<void> {
 | 
			
		||||
        if (!CoreApp.instance.isAndroid()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await Push.instance.createChannel({
 | 
			
		||||
                id: 'PushPluginChannel',
 | 
			
		||||
                description: Translate.instance.instant('core.misc'),
 | 
			
		||||
                importance: 4,
 | 
			
		||||
            });
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            this.logger.error('Error changing push channel name', error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Enable or disable Firebase analytics.
 | 
			
		||||
     *
 | 
			
		||||
     * @param enable Whether to enable or disable.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async enableAnalytics(enable: boolean): Promise<void> {
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
        const win = <any> window; // This feature is only present in our fork of the plugin.
 | 
			
		||||
 | 
			
		||||
        if (!CoreConstants.CONFIG.enableanalytics || !win.PushNotification?.enableAnalytics) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const deferred = CoreUtils.instance.promiseDefer<void>();
 | 
			
		||||
 | 
			
		||||
        win.PushNotification.enableAnalytics(deferred.resolve, (error) => {
 | 
			
		||||
            this.logger.error('Error enabling or disabling Firebase analytics', enable, error);
 | 
			
		||||
            deferred.resolve();
 | 
			
		||||
        }, !!enable);
 | 
			
		||||
 | 
			
		||||
        await deferred.promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns options for push notifications based on device.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise with the push options resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async getOptions(): Promise<PushOptions> {
 | 
			
		||||
        let soundEnabled = true;
 | 
			
		||||
 | 
			
		||||
        if (CoreLocalNotifications.instance.canDisableSound()) {
 | 
			
		||||
            soundEnabled = await CoreConfig.instance.get<boolean>(CoreConstants.SETTINGS_NOTIFICATION_SOUND, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            android: {
 | 
			
		||||
                sound: !!soundEnabled,
 | 
			
		||||
                icon: 'smallicon',
 | 
			
		||||
                iconColor: CoreConstants.CONFIG.notificoncolor,
 | 
			
		||||
            },
 | 
			
		||||
            ios: {
 | 
			
		||||
                alert: 'true',
 | 
			
		||||
                badge: true,
 | 
			
		||||
                sound: !!soundEnabled,
 | 
			
		||||
            },
 | 
			
		||||
            windows: {
 | 
			
		||||
                sound: !!soundEnabled,
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the pushID for this device.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Push ID.
 | 
			
		||||
     */
 | 
			
		||||
    getPushId(): string | undefined {
 | 
			
		||||
        return this.pushID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get data to register the device in Moodle.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Data.
 | 
			
		||||
     */
 | 
			
		||||
    protected getRegisterData(): CoreUserAddUserDeviceWSParams {
 | 
			
		||||
        if (!this.pushID) {
 | 
			
		||||
            throw new CoreError('Cannot get register data because pushID is not set.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            appid:      CoreConstants.CONFIG.app_id,
 | 
			
		||||
            name:       Device.instance.manufacturer || '',
 | 
			
		||||
            model:      Device.instance.model,
 | 
			
		||||
            platform:   Device.instance.platform + '-fcm',
 | 
			
		||||
            version:    Device.instance.version,
 | 
			
		||||
            pushid:     this.pushID,
 | 
			
		||||
            uuid:       Device.instance.uuid,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get Sitebadge  counter from the database.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID.
 | 
			
		||||
     * @return Promise resolved with the stored badge counter for the site.
 | 
			
		||||
     */
 | 
			
		||||
    getSiteCounter(siteId: string): Promise<number> {
 | 
			
		||||
        return this.getAddonBadge(siteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Log a firebase event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name Name of the event.
 | 
			
		||||
     * @param data Data of the event.
 | 
			
		||||
     * @param filter Whether to filter the data. This is useful when logging a full notification.
 | 
			
		||||
     * @return Promise resolved when done. This promise is never rejected.
 | 
			
		||||
     */
 | 
			
		||||
    async logEvent(name: string, data: Record<string, unknown>, filter?: boolean): Promise<void> {
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
        const win = <any> window; // This feature is only present in our fork of the plugin.
 | 
			
		||||
 | 
			
		||||
        if (!CoreConstants.CONFIG.enableanalytics || !win.PushNotification?.logEvent) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if the analytics is enabled by the user.
 | 
			
		||||
        const enabled = await CoreConfig.instance.get<boolean>(CoreConstants.SETTINGS_ANALYTICS_ENABLED, true);
 | 
			
		||||
        if (!enabled) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const deferred = CoreUtils.instance.promiseDefer<void>();
 | 
			
		||||
 | 
			
		||||
        win.PushNotification.logEvent(deferred.resolve, (error) => {
 | 
			
		||||
            this.logger.error('Error logging firebase event', name, error);
 | 
			
		||||
            deferred.resolve();
 | 
			
		||||
        }, name, data, !!filter);
 | 
			
		||||
 | 
			
		||||
        await deferred.promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Log a firebase view_item event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param itemId The item ID.
 | 
			
		||||
     * @param itemName The item name.
 | 
			
		||||
     * @param itemCategory The item category.
 | 
			
		||||
     * @param wsName Name of the WS.
 | 
			
		||||
     * @param data Other data to pass to the event.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when done. This promise is never rejected.
 | 
			
		||||
     */
 | 
			
		||||
    logViewEvent(
 | 
			
		||||
        itemId: number | string | undefined,
 | 
			
		||||
        itemName: string | undefined,
 | 
			
		||||
        itemCategory: string | undefined,
 | 
			
		||||
        wsName: string,
 | 
			
		||||
        data?: Record<string, unknown>,
 | 
			
		||||
        siteId?: string,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        data = data || {};
 | 
			
		||||
 | 
			
		||||
        // Add "moodle" to the name of all extra params.
 | 
			
		||||
        data = CoreUtils.instance.prefixKeys(data, 'moodle');
 | 
			
		||||
        data.moodleaction = wsName;
 | 
			
		||||
        data.moodlesiteid = siteId || CoreSites.instance.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        if (itemId) {
 | 
			
		||||
            data.item_id = itemId;
 | 
			
		||||
        }
 | 
			
		||||
        if (itemName) {
 | 
			
		||||
            data.item_name = itemName;
 | 
			
		||||
        }
 | 
			
		||||
        if (itemCategory) {
 | 
			
		||||
            data.item_category = itemCategory;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.logEvent('view_item', data, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Log a firebase view_item_list event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param itemCategory The item category.
 | 
			
		||||
     * @param wsName Name of the WS.
 | 
			
		||||
     * @param data Other data to pass to the event.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when done. This promise is never rejected.
 | 
			
		||||
     */
 | 
			
		||||
    logViewListEvent(itemCategory: string, wsName: string, data?: Record<string, unknown>, siteId?: string): Promise<void> {
 | 
			
		||||
        data = data || {};
 | 
			
		||||
 | 
			
		||||
        // Add "moodle" to the name of all extra params.
 | 
			
		||||
        data = CoreUtils.instance.prefixKeys(data, 'moodle');
 | 
			
		||||
        data.moodleaction = wsName;
 | 
			
		||||
        data.moodlesiteid = siteId || CoreSites.instance.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        if (itemCategory) {
 | 
			
		||||
            data.item_category = itemCategory;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.logEvent('view_item_list', data, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Function called when a push notification is clicked. Redirect the user to the right state.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification Notification.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async notificationClicked(data: CorePushNotificationsNotificationBasicData): Promise<void> {
 | 
			
		||||
        await ApplicationInit.instance.donePromise;
 | 
			
		||||
 | 
			
		||||
        CorePushNotificationsDelegate.instance.clicked(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This function is called when we receive a Notification from APNS or a message notification from GCM.
 | 
			
		||||
     * The app can be in foreground or background,
 | 
			
		||||
     * if we are in background this code is executed when we open the app clicking in the notification bar.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification Notification received.
 | 
			
		||||
     */
 | 
			
		||||
    async onMessageReceived(notification: NotificationEventResponse): Promise<void> {
 | 
			
		||||
        const rawData: CorePushNotificationsNotificationBasicRawData = notification ? notification.additionalData : {};
 | 
			
		||||
 | 
			
		||||
        // Parse some fields and add some extra data.
 | 
			
		||||
        const data: CorePushNotificationsNotificationBasicData = Object.assign(rawData, {
 | 
			
		||||
            title: notification.title,
 | 
			
		||||
            message: notification.message,
 | 
			
		||||
            customdata: typeof rawData.customdata == 'string' ?
 | 
			
		||||
                CoreTextUtils.instance.parseJSON<Record<string, unknown>>(rawData.customdata, {}) : rawData.customdata,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let site: CoreSite | undefined;
 | 
			
		||||
 | 
			
		||||
        if (data.site) {
 | 
			
		||||
            site = await CoreSites.instance.getSite(data.site);
 | 
			
		||||
        } else if (data.siteurl) {
 | 
			
		||||
            site = await CoreSites.instance.getSiteByUrl(data.siteurl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        data.site = site?.getId();
 | 
			
		||||
 | 
			
		||||
        if (!CoreUtils.instance.isTrueOrOne(data.foreground)) {
 | 
			
		||||
            // The notification was clicked.
 | 
			
		||||
            return this.notificationClicked(data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If the app is in foreground when the notification is received, it's not shown. Let's show it ourselves.
 | 
			
		||||
        if (!CoreLocalNotifications.instance.isAvailable()) {
 | 
			
		||||
            return this.notifyReceived(notification, data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const localNotif: ILocalNotification = {
 | 
			
		||||
            id: Number(data.notId) || 1,
 | 
			
		||||
            data: data,
 | 
			
		||||
            title: notification.title,
 | 
			
		||||
            text: notification.message,
 | 
			
		||||
            channel: 'PushPluginChannel',
 | 
			
		||||
        };
 | 
			
		||||
        const isAndroid = CoreApp.instance.isAndroid();
 | 
			
		||||
        const extraFeatures = CoreUtils.instance.isTrueOrOne(data.extrafeatures);
 | 
			
		||||
 | 
			
		||||
        if (extraFeatures && isAndroid && CoreUtils.instance.isFalseOrZero(data.notif)) {
 | 
			
		||||
            // It's a message, use messaging style. Ionic Native doesn't specify this option.
 | 
			
		||||
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
            (<any> localNotif).text = [
 | 
			
		||||
                {
 | 
			
		||||
                    message: notification.message,
 | 
			
		||||
                    person: data.conversationtype == '2' ? data.userfromfullname : '',
 | 
			
		||||
                },
 | 
			
		||||
            ];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (extraFeatures && isAndroid) {
 | 
			
		||||
            // Use a different icon if needed.
 | 
			
		||||
            localNotif.icon = notification.image;
 | 
			
		||||
            // This feature isn't supported by the official plugin, we use a fork.
 | 
			
		||||
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
            (<any> localNotif).iconType = data['image-type'];
 | 
			
		||||
 | 
			
		||||
            localNotif.summary = data.summaryText;
 | 
			
		||||
 | 
			
		||||
            if (data.picture) {
 | 
			
		||||
                localNotif.attachments = [data.picture];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CoreLocalNotifications.instance.schedule(localNotif, CorePushNotificationsProvider.COMPONENT, data.site || '', true);
 | 
			
		||||
 | 
			
		||||
        await this.notifyReceived(notification, data);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Notify that a notification was received.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification Notification.
 | 
			
		||||
     * @param data Notification data.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async notifyReceived(
 | 
			
		||||
        notification: NotificationEventResponse,
 | 
			
		||||
        data: CorePushNotificationsNotificationBasicData,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        await ApplicationInit.instance.donePromise;
 | 
			
		||||
 | 
			
		||||
        CorePushNotificationsDelegate.instance.received(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Unregisters a device from a certain Moodle site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param site Site to unregister from.
 | 
			
		||||
     * @return Promise resolved when device is unregistered.
 | 
			
		||||
     */
 | 
			
		||||
    async unregisterDeviceOnMoodle(site: CoreSite): Promise<void> {
 | 
			
		||||
        if (!site || !CoreApp.instance.isMobile()) {
 | 
			
		||||
            throw new CoreError('Cannot unregister device');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.logger.debug(`Unregister device on Moodle: '${site.getId()}'`);
 | 
			
		||||
 | 
			
		||||
        const db = await this.appDB;
 | 
			
		||||
        const data: CoreUserRemoveUserDeviceWSParams = {
 | 
			
		||||
            appid: CoreConstants.CONFIG.app_id,
 | 
			
		||||
            uuid:  Device.instance.uuid,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const response = await site.write<CoreUserRemoveUserDeviceWSResponse>('core_user_remove_user_device', data);
 | 
			
		||||
 | 
			
		||||
            if (!response || !response.removed) {
 | 
			
		||||
                throw new CoreError('Cannot unregister device');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await CoreUtils.instance.ignoreErrors(Promise.all([
 | 
			
		||||
                // Remove the device from the local DB.
 | 
			
		||||
                site.getDb().deleteRecords(REGISTERED_DEVICES_TABLE_NAME, this.getRegisterData()),
 | 
			
		||||
                // Remove pending unregisters for this site.
 | 
			
		||||
                db.deleteRecords(PENDING_UNREGISTER_TABLE_NAME, { siteid: site.getId() }),
 | 
			
		||||
            ]));
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (CoreUtils.instance.isWebServiceError(error)) {
 | 
			
		||||
                throw error;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Store the pending unregister so it's retried again later.
 | 
			
		||||
            const entry: CorePushNotificationsPendingUnregisterDBRecord = {
 | 
			
		||||
                siteid: site.getId(),
 | 
			
		||||
                siteurl: site.getURL(),
 | 
			
		||||
                token: site.getToken(),
 | 
			
		||||
                info: JSON.stringify(site.getInfo()),
 | 
			
		||||
            };
 | 
			
		||||
            await db.insertRecord(PENDING_UNREGISTER_TABLE_NAME, entry);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update Counter for an addon. It will update the refered siteId counter and the total badge.
 | 
			
		||||
     * It will return the updated addon counter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param addon Registered addon name to set the badge number.
 | 
			
		||||
     * @param value The number to be stored.
 | 
			
		||||
     * @param siteId Site ID. If not defined, use current site.
 | 
			
		||||
     * @return Promise resolved with the stored badge counter for the addon on the site.
 | 
			
		||||
     */
 | 
			
		||||
    async updateAddonCounter(addon: string, value: number, siteId?: string): Promise<number> {
 | 
			
		||||
        if (!CorePushNotificationsDelegate.instance.isCounterHandlerRegistered(addon)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        siteId = siteId || CoreSites.instance.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        await this.saveAddonBadge(value, siteId, addon);
 | 
			
		||||
        await this.updateSiteCounter(siteId);
 | 
			
		||||
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update total badge counter of the app.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved with the stored badge counter for the site.
 | 
			
		||||
     */
 | 
			
		||||
    async updateAppCounter(): Promise<number> {
 | 
			
		||||
        const sitesIds = await CoreSites.instance.getSitesIds();
 | 
			
		||||
 | 
			
		||||
        const counters = await Promise.all(sitesIds.map((siteId) => this.getAddonBadge(siteId)));
 | 
			
		||||
 | 
			
		||||
        const total = counters.reduce((previous, counter) => previous + counter, 0);
 | 
			
		||||
 | 
			
		||||
        if (!CoreApp.instance.isMobile()) {
 | 
			
		||||
            // Browser doesn't have an app badge, stop.
 | 
			
		||||
            return total;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set the app badge.
 | 
			
		||||
        await Badge.instance.set(total);
 | 
			
		||||
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update counter for a site using the stored addon data. It will update the total badge application number.
 | 
			
		||||
     * It will return the updated site counter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID.
 | 
			
		||||
     * @return Promise resolved with the stored badge counter for the site.
 | 
			
		||||
     */
 | 
			
		||||
    async updateSiteCounter(siteId: string): Promise<number> {
 | 
			
		||||
        const addons = CorePushNotificationsDelegate.instance.getCounterHandlers();
 | 
			
		||||
 | 
			
		||||
        const counters = await Promise.all(Object.values(addons).map((addon) => this.getAddonBadge(siteId, addon)));
 | 
			
		||||
 | 
			
		||||
        const total = counters.reduce((previous, counter) => previous + counter, 0);
 | 
			
		||||
 | 
			
		||||
        // Save the counter on site.
 | 
			
		||||
        await this.saveAddonBadge(total, siteId);
 | 
			
		||||
 | 
			
		||||
        await this.updateAppCounter();
 | 
			
		||||
 | 
			
		||||
        return total;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register a device in Apple APNS or Google GCM.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when the device is registered.
 | 
			
		||||
     */
 | 
			
		||||
    async registerDevice(): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            // Check if sound is enabled for notifications.
 | 
			
		||||
            const options = await this.getOptions();
 | 
			
		||||
 | 
			
		||||
            const pushObject = Push.instance.init(options);
 | 
			
		||||
 | 
			
		||||
            pushObject.on('notification').subscribe((notification: NotificationEventResponse) => {
 | 
			
		||||
                // Execute the callback in the Angular zone, so change detection doesn't stop working.
 | 
			
		||||
                NgZone.instance.run(() => {
 | 
			
		||||
                    this.logger.log('Received a notification', notification);
 | 
			
		||||
                    this.onMessageReceived(notification);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            pushObject.on('registration').subscribe((data: RegistrationEventResponse) => {
 | 
			
		||||
                // Execute the callback in the Angular zone, so change detection doesn't stop working.
 | 
			
		||||
                NgZone.instance.run(() => {
 | 
			
		||||
                    this.pushID = data.registrationId;
 | 
			
		||||
                    if (!CoreSites.instance.isLoggedIn()) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    this.registerDeviceOnMoodle().catch((error) => {
 | 
			
		||||
                        this.logger.warn('Can\'t register device', error);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            pushObject.on('error').subscribe((error: Error) => {
 | 
			
		||||
                // Execute the callback in the Angular zone, so change detection doesn't stop working.
 | 
			
		||||
                NgZone.instance.run(() => {
 | 
			
		||||
                    this.logger.warn('Error with Push plugin', error);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            this.logger.warn(error);
 | 
			
		||||
 | 
			
		||||
            throw error;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Registers a device on a Moodle site if needed.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @param forceUnregister Whether to force unregister and register.
 | 
			
		||||
     * @return Promise resolved when device is registered.
 | 
			
		||||
     */
 | 
			
		||||
    async registerDeviceOnMoodle(siteId?: string, forceUnregister?: boolean): Promise<void> {
 | 
			
		||||
        this.logger.debug('Register device on Moodle.');
 | 
			
		||||
 | 
			
		||||
        if (!this.canRegisterOnMoodle()) {
 | 
			
		||||
            return Promise.reject(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.instance.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            const data = this.getRegisterData();
 | 
			
		||||
            let result = {
 | 
			
		||||
                unregister: true,
 | 
			
		||||
                register: true,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (!forceUnregister) {
 | 
			
		||||
                // Check if the device is already registered.
 | 
			
		||||
                result = await this.shouldRegister(data, site);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result.unregister) {
 | 
			
		||||
                // Unregister the device first.
 | 
			
		||||
                await CoreUtils.instance.ignoreErrors(this.unregisterDeviceOnMoodle(site));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result.register) {
 | 
			
		||||
                // Now register the device.
 | 
			
		||||
                await site.write('core_user_add_user_device', CoreUtils.instance.clone(data));
 | 
			
		||||
 | 
			
		||||
                CoreEvents.trigger(CoreEvents.DEVICE_REGISTERED_IN_MOODLE, {}, site.getId());
 | 
			
		||||
 | 
			
		||||
                // Insert the device in the local DB.
 | 
			
		||||
                try {
 | 
			
		||||
                    await site.getDb().insertRecord(REGISTERED_DEVICES_TABLE_NAME, data);
 | 
			
		||||
                } catch (err) {
 | 
			
		||||
                    // Ignore errors.
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            // Remove pending unregisters for this site.
 | 
			
		||||
            const db = await this.appDB;
 | 
			
		||||
            await CoreUtils.instance.ignoreErrors(db.deleteRecords(PENDING_UNREGISTER_TABLE_NAME, { siteid: site.getId() }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the addon/site badge counter from the database.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID.
 | 
			
		||||
     * @param addon Registered addon name. If not defined it will store the site total.
 | 
			
		||||
     * @return Promise resolved with the stored badge counter for the addon or site or 0 if none.
 | 
			
		||||
     */
 | 
			
		||||
    protected async getAddonBadge(siteId?: string, addon: string = 'site'): Promise<number> {
 | 
			
		||||
        try {
 | 
			
		||||
            const db = await this.appDB;
 | 
			
		||||
            const entry = await db.getRecord<CorePushNotificationsBadgeDBRecord>(BADGE_TABLE_NAME, { siteid: siteId, addon });
 | 
			
		||||
 | 
			
		||||
            return entry?.number || 0;
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retry pending unregisters.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId If defined, retry only for that site if needed. Otherwise, retry all pending unregisters.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async retryUnregisters(siteId?: string): Promise<void> {
 | 
			
		||||
 | 
			
		||||
        const db = await this.appDB;
 | 
			
		||||
        let results: CorePushNotificationsPendingUnregisterDBRecord[];
 | 
			
		||||
 | 
			
		||||
        if (siteId) {
 | 
			
		||||
            // Check if the site has a pending unregister.
 | 
			
		||||
            results = await db.getRecords<CorePushNotificationsPendingUnregisterDBRecord>(PENDING_UNREGISTER_TABLE_NAME, {
 | 
			
		||||
                siteid: siteId,
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Get all pending unregisters.
 | 
			
		||||
            results = await db.getAllRecords<CorePushNotificationsPendingUnregisterDBRecord>(PENDING_UNREGISTER_TABLE_NAME);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await Promise.all(results.map(async (result) => {
 | 
			
		||||
            // Create a temporary site to unregister.
 | 
			
		||||
            const tmpSite = new CoreSite(
 | 
			
		||||
                result.siteid,
 | 
			
		||||
                result.siteurl,
 | 
			
		||||
                result.token,
 | 
			
		||||
                CoreTextUtils.instance.parseJSON<CoreSiteInfo | null>(result.info, null) || undefined,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            await this.unregisterDeviceOnMoodle(tmpSite);
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Save the addon/site badgecounter on the database.
 | 
			
		||||
     *
 | 
			
		||||
     * @param value The number to be stored.
 | 
			
		||||
     * @param siteId Site ID. If not defined, use current site.
 | 
			
		||||
     * @param addon Registered addon name. If not defined it will store the site total.
 | 
			
		||||
     * @return Promise resolved with the stored badge counter for the addon or site.
 | 
			
		||||
     */
 | 
			
		||||
    protected async saveAddonBadge(value: number, siteId?: string, addon: string = 'site'): Promise<number> {
 | 
			
		||||
        siteId = siteId || CoreSites.instance.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        const entry: CorePushNotificationsBadgeDBRecord = {
 | 
			
		||||
            siteid: siteId,
 | 
			
		||||
            addon,
 | 
			
		||||
            number: value, // eslint-disable-line id-blacklist
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const db = await this.appDB;
 | 
			
		||||
        await db.insertRecord(BADGE_TABLE_NAME, entry);
 | 
			
		||||
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if device should be registered (and unregistered first).
 | 
			
		||||
     *
 | 
			
		||||
     * @param data Data of the device.
 | 
			
		||||
     * @param site Site to use.
 | 
			
		||||
     * @return Promise resolved with booleans: whether to register/unregister.
 | 
			
		||||
     */
 | 
			
		||||
    protected async shouldRegister(
 | 
			
		||||
        data: CoreUserAddUserDeviceWSParams,
 | 
			
		||||
        site: CoreSite,
 | 
			
		||||
    ): Promise<{register: boolean; unregister: boolean}> {
 | 
			
		||||
 | 
			
		||||
        // Check if the device is already registered.
 | 
			
		||||
        const records = await CoreUtils.instance.ignoreErrors(
 | 
			
		||||
            site.getDb().getRecords<CorePushNotificationsRegisteredDeviceDBRecord>(REGISTERED_DEVICES_TABLE_NAME, {
 | 
			
		||||
                appid: data.appid,
 | 
			
		||||
                uuid: data.uuid,
 | 
			
		||||
                name: data.name,
 | 
			
		||||
                model: data.model,
 | 
			
		||||
                platform: data.platform,
 | 
			
		||||
            }),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let isStored = false;
 | 
			
		||||
        let versionOrPushChanged = false;
 | 
			
		||||
 | 
			
		||||
        (records || []).forEach((record) => {
 | 
			
		||||
            if (record.version == data.version && record.pushid == data.pushid) {
 | 
			
		||||
                // The device is already stored.
 | 
			
		||||
                isStored = true;
 | 
			
		||||
            } else {
 | 
			
		||||
                // The version or pushid has changed.
 | 
			
		||||
                versionOrPushChanged = true;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (isStored) {
 | 
			
		||||
            // The device has already been registered, no need to register it again.
 | 
			
		||||
            return {
 | 
			
		||||
                register: false,
 | 
			
		||||
                unregister: false,
 | 
			
		||||
            };
 | 
			
		||||
        } else if (versionOrPushChanged) {
 | 
			
		||||
            // This data can be updated by calling register WS, no need to call unregister.
 | 
			
		||||
            return {
 | 
			
		||||
                register: true,
 | 
			
		||||
                unregister: false,
 | 
			
		||||
            };
 | 
			
		||||
        } else {
 | 
			
		||||
            return {
 | 
			
		||||
                register: true,
 | 
			
		||||
                unregister: true,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CorePushNotifications extends makeSingleton(CorePushNotificationsProvider) {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Additional data sent in push notifications.
 | 
			
		||||
 */
 | 
			
		||||
export type CorePushNotificationsNotificationBasicRawData = {
 | 
			
		||||
    customdata?: string; // Custom data.
 | 
			
		||||
    extrafeatures?: string; // "1" if the notification uses extrafeatures, "0" otherwise.
 | 
			
		||||
    foreground?: boolean; // Whether the app was in foreground.
 | 
			
		||||
    'image-type'?: string; // How to display the notification image.
 | 
			
		||||
    moodlecomponent?: string; // Moodle component that triggered the notification.
 | 
			
		||||
    name?: string; // A name to identify the type of notification.
 | 
			
		||||
    notId?: string; // Notification ID.
 | 
			
		||||
    notif?: string; // "1" if it's a notification, "0" if it's a Moodle message.
 | 
			
		||||
    site?: string; // ID of the site sending the notification.
 | 
			
		||||
    siteurl?: string; // URL of the site the notification is related to.
 | 
			
		||||
    usertoid?: string; // ID of user receiving the push.
 | 
			
		||||
    conversationtype?: string; // Conversation type. Only if it's a push generated by a Moodle message.
 | 
			
		||||
    userfromfullname?: string; // Fullname of user sending the push. Only if it's a push generated by a Moodle message.
 | 
			
		||||
    userfromid?: string; // ID of user sending the push. Only if it's a push generated by a Moodle message.
 | 
			
		||||
    picture?: string; // Notification big picture. "Extra" feature.
 | 
			
		||||
    summaryText?: string; // Notification summary text. "Extra" feature.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Additional data sent in push notifications, with some calculated data.
 | 
			
		||||
 */
 | 
			
		||||
export type CorePushNotificationsNotificationBasicData = Omit<CorePushNotificationsNotificationBasicRawData, 'customdata'> & {
 | 
			
		||||
    title?: string; // Notification title.
 | 
			
		||||
    message?: string; // Notification message.
 | 
			
		||||
    customdata?: Record<string, unknown>; // Parsed custom data.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of core_user_remove_user_device WS.
 | 
			
		||||
 */
 | 
			
		||||
export type CoreUserRemoveUserDeviceWSParams = {
 | 
			
		||||
    uuid: string; // The device UUID.
 | 
			
		||||
    appid?: string; // The app id, if empty devices matching the UUID for the user will be removed.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data returned by core_user_remove_user_device WS.
 | 
			
		||||
 */
 | 
			
		||||
export type CoreUserRemoveUserDeviceWSResponse = {
 | 
			
		||||
    removed: boolean; // True if removed, false if not removed because it doesn't exists.
 | 
			
		||||
    warnings?: CoreWSExternalWarning[];
 | 
			
		||||
};
 | 
			
		||||
/**
 | 
			
		||||
 * Params of core_user_add_user_device WS.
 | 
			
		||||
 */
 | 
			
		||||
export type CoreUserAddUserDeviceWSParams = {
 | 
			
		||||
    appid: string; // The app id, usually something like com.moodle.moodlemobile.
 | 
			
		||||
    name: string; // The device name, 'occam' or 'iPhone' etc.
 | 
			
		||||
    model: string; // The device model 'Nexus4' or 'iPad1,1' etc.
 | 
			
		||||
    platform: string; // The device platform 'iOS' or 'Android' etc.
 | 
			
		||||
    version: string; // The device version '6.1.2' or '4.2.2' etc.
 | 
			
		||||
    pushid: string; // The device PUSH token/key/identifier/registration id.
 | 
			
		||||
    uuid: string; // The device UUID.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data returned by core_user_add_user_device WS.
 | 
			
		||||
 */
 | 
			
		||||
export type CoreUserAddUserDeviceWSResponse = CoreWSExternalWarning[][];
 | 
			
		||||
@ -22,6 +22,7 @@ import { CoreFile } from '@services/file';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Device Info to be shown and copied to clipboard.
 | 
			
		||||
@ -50,7 +51,7 @@ interface CoreSettingsDeviceInfo {
 | 
			
		||||
    osVersion?: string;
 | 
			
		||||
    model?: string;
 | 
			
		||||
    uuid?: string;
 | 
			
		||||
    pushId: string;
 | 
			
		||||
    pushId?: string;
 | 
			
		||||
    localNotifAvailable: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -86,7 +87,7 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
 | 
			
		||||
            networkStatus: appProvider.isOnline() ? 'online' : 'offline',
 | 
			
		||||
            wifiConnection: appProvider.isWifi() ? 'yes' : 'no',
 | 
			
		||||
            localNotifAvailable: CoreLocalNotifications.instance.isAvailable() ? 'yes' : 'no',
 | 
			
		||||
            pushId: '',// TODO pushNotificationsProvider.getPushId(),
 | 
			
		||||
            pushId: CorePushNotifications.instance.getPushId(),
 | 
			
		||||
            deviceType: '',
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ import { CoreConfig } from '@services/config';
 | 
			
		||||
import { CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreLang } from '@services/lang';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
// import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
 | 
			
		||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
 | 
			
		||||
import { CoreSettingsHelper, CoreColorScheme } from '../../services/settings-helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -160,7 +160,7 @@ export class CoreSettingsGeneralPage {
 | 
			
		||||
     * @todo
 | 
			
		||||
     */
 | 
			
		||||
    async analyticsEnabledChanged(): Promise<void> {
 | 
			
		||||
        // await this.pushNotificationsProvider.enableAnalytics(this.analyticsEnabled);
 | 
			
		||||
        await CorePushNotifications.instance.enableAnalytics(this.analyticsEnabled);
 | 
			
		||||
 | 
			
		||||
        CoreConfig.instance.set(CoreConstants.SETTINGS_ANALYTICS_ENABLED, this.analyticsEnabled ? 1 : 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ import { CoreEvents, CoreEventUserDeletedData } from '@singletons/events';
 | 
			
		||||
import { CoreStatusWithWarningsWSResponse, CoreWSExternalWarning } from '@services/ws';
 | 
			
		||||
import { CoreError } from '@classes/errors/error';
 | 
			
		||||
import { USERS_TABLE_NAME, CoreUserDBRecord } from './database/user';
 | 
			
		||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'mmUser:';
 | 
			
		||||
 | 
			
		||||
@ -526,7 +527,7 @@ export class CoreUserProvider {
 | 
			
		||||
            params.courseid = courseId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // @todo this.pushNotificationsProvider.logViewEvent(userId, name, 'user', wsName, {courseid: courseId});
 | 
			
		||||
        CorePushNotifications.instance.logViewEvent(userId, name, 'user', wsName, { courseid: courseId });
 | 
			
		||||
 | 
			
		||||
        return site.write(wsName, params);
 | 
			
		||||
    }
 | 
			
		||||
@ -544,7 +545,7 @@ export class CoreUserProvider {
 | 
			
		||||
            courseid: courseId,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // @todo this.pushNotificationsProvider.logViewListEvent('user', 'core_user_view_user_list', params);
 | 
			
		||||
        CorePushNotifications.instance.logViewListEvent('user', 'core_user_view_user_list', params);
 | 
			
		||||
 | 
			
		||||
        return site.write('core_user_view_user_list', params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -45,8 +45,7 @@ export class CoreLocalNotificationsProvider {
 | 
			
		||||
    protected logger: CoreLogger;
 | 
			
		||||
    protected codes: { [s: string]: number } = {};
 | 
			
		||||
    protected codeRequestsQueue: {[key: string]: CodeRequestsQueueItem} = {};
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
    protected observables: {[eventName: string]: {[component: string]: Subject<any>}} = {};
 | 
			
		||||
    protected observables: {[eventName: string]: {[component: string]: Subject<unknown>}} = {};
 | 
			
		||||
 | 
			
		||||
    protected triggerSubscription?: Subscription;
 | 
			
		||||
    protected clickSubscription?: Subscription;
 | 
			
		||||
@ -373,8 +372,7 @@ export class CoreLocalNotificationsProvider {
 | 
			
		||||
     *
 | 
			
		||||
     * @param data Data received by the notification.
 | 
			
		||||
     */
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
    notifyClick(data: any): void {
 | 
			
		||||
    notifyClick(data: Record<string, unknown>): void {
 | 
			
		||||
        this.notifyEvent('click', data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -384,11 +382,10 @@ export class CoreLocalNotificationsProvider {
 | 
			
		||||
     * @param eventName Name of the event to notify.
 | 
			
		||||
     * @param data Data received by the notification.
 | 
			
		||||
     */
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
    notifyEvent(eventName: string, data: any): void {
 | 
			
		||||
    notifyEvent(eventName: string, data: Record<string, unknown>): void {
 | 
			
		||||
        // Execute the code in the Angular zone, so change detection doesn't stop working.
 | 
			
		||||
        NgZone.instance.run(() => {
 | 
			
		||||
            const component = data.component;
 | 
			
		||||
            const component = <string> data.component;
 | 
			
		||||
            if (component) {
 | 
			
		||||
                if (this.observables[eventName] && this.observables[eventName][component]) {
 | 
			
		||||
                    this.observables[eventName][component].next(data);
 | 
			
		||||
@ -403,8 +400,7 @@ export class CoreLocalNotificationsProvider {
 | 
			
		||||
     * @param data Notification data.
 | 
			
		||||
     * @return Parsed data.
 | 
			
		||||
     */
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
    protected parseNotificationData(data: any): any {
 | 
			
		||||
    protected parseNotificationData(data: unknown): unknown {
 | 
			
		||||
        if (!data) {
 | 
			
		||||
            return {};
 | 
			
		||||
        } else if (typeof data == 'string') {
 | 
			
		||||
@ -457,8 +453,8 @@ export class CoreLocalNotificationsProvider {
 | 
			
		||||
     * @param callback Function to call with the data received by the notification.
 | 
			
		||||
     * @return Object with an "off" property to stop listening for clicks.
 | 
			
		||||
     */
 | 
			
		||||
    registerClick(component: string, callback: CoreLocalNotificationsClickCallback): CoreEventObserver {
 | 
			
		||||
        return this.registerObserver('click', component, callback);
 | 
			
		||||
    registerClick<T = unknown>(component: string, callback: CoreLocalNotificationsClickCallback<T>): CoreEventObserver {
 | 
			
		||||
        return this.registerObserver<T>('click', component, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -469,7 +465,11 @@ export class CoreLocalNotificationsProvider {
 | 
			
		||||
     * @param callback Function to call with the data received by the notification.
 | 
			
		||||
     * @return Object with an "off" property to stop listening for events.
 | 
			
		||||
     */
 | 
			
		||||
    registerObserver<T>(eventName: string, component: string, callback: CoreLocalNotificationsClickCallback): CoreEventObserver {
 | 
			
		||||
    registerObserver<T = unknown>(
 | 
			
		||||
        eventName: string,
 | 
			
		||||
        component: string,
 | 
			
		||||
        callback: CoreLocalNotificationsClickCallback<T>,
 | 
			
		||||
    ): CoreEventObserver {
 | 
			
		||||
        this.logger.debug(`Register observer '${component}' for event '${eventName}'.`);
 | 
			
		||||
 | 
			
		||||
        if (typeof this.observables[eventName] == 'undefined') {
 | 
			
		||||
 | 
			
		||||
@ -971,6 +971,23 @@ export class CoreSitesProvider {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Finds a site with a certain URL. It will return the first site found.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteUrl The site URL.
 | 
			
		||||
     * @return Promise resolved with the site.
 | 
			
		||||
     */
 | 
			
		||||
    async getSiteByUrl(siteUrl: string): Promise<CoreSite> {
 | 
			
		||||
        const db = await this.appDB;
 | 
			
		||||
        const data = await db.getRecord<SiteDBEntry>(SITES_TABLE_NAME, { siteUrl });
 | 
			
		||||
 | 
			
		||||
        if (typeof this.sites[data.id] != 'undefined') {
 | 
			
		||||
            return this.sites[data.id];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.makeSiteFromSiteListEntry(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a site from an entry of the sites list DB. The new site is added to the list of "cached" sites: this.sites.
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,7 @@ export class CoreEvents {
 | 
			
		||||
    static readonly SITE_STORAGE_DELETED = 'site_storage_deleted';
 | 
			
		||||
    static readonly FORM_ACTION = 'form_action';
 | 
			
		||||
    static readonly ACTIVITY_DATA_SENT = 'activity_data_sent';
 | 
			
		||||
    static readonly DEVICE_REGISTERED_IN_MOODLE = 'device_registered_in_moodle';
 | 
			
		||||
 | 
			
		||||
    protected static logger = CoreLogger.getInstance('CoreEvents');
 | 
			
		||||
    protected static observables: { [eventName: string]: Subject<unknown> } = {};
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ import {
 | 
			
		||||
    ActionSheetController as ActionSheetControllerService,
 | 
			
		||||
} from '@ionic/angular';
 | 
			
		||||
 | 
			
		||||
import { Badge as BadgeService } from '@ionic-native/badge/ngx';
 | 
			
		||||
import { Camera as CameraService } from '@ionic-native/camera/ngx';
 | 
			
		||||
import { Chooser as ChooserService } from '@ionic-native/chooser/ngx';
 | 
			
		||||
import { Clipboard as ClipboardService } from '@ionic-native/clipboard/ngx';
 | 
			
		||||
@ -111,6 +112,7 @@ export function makeSingleton<Service>(injectionToken: Type<Service> | Type<unkn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert ionic-native services to singleton.
 | 
			
		||||
export class Badge extends makeSingleton(BadgeService) {}
 | 
			
		||||
export class Camera extends makeSingleton(CameraService) {}
 | 
			
		||||
export class Chooser extends makeSingleton(ChooserService) {}
 | 
			
		||||
export class Clipboard extends makeSingleton(ClipboardService) {}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user