MOBILE-2327 pushnotifications: Add push notifications delegate
parent
0c4f834c0a
commit
b9c0bb5653
|
@ -35,7 +35,7 @@ export class AddonFilesProvider {
|
|||
* @return {boolean} Whether the WS is available, false otherwise.
|
||||
*/
|
||||
canGetPrivateFilesInfo(): boolean {
|
||||
return this.sitesProvider.getCurrentSite().wsAvailable('core_user_get_private_files_info');
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_user_get_private_files_info');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,10 @@ import { AddonMessagesDiscussionLinkHandler } from './providers/discussion-link-
|
|||
import { AddonMessagesIndexLinkHandler } from './providers/index-link-handler';
|
||||
import { AddonMessagesSyncCronHandler } from './providers/sync-cron-handler';
|
||||
import { CoreEventsProvider } from '../../providers/events';
|
||||
import { CoreAppProvider } from '../../providers/app';
|
||||
import { CoreSitesProvider } from '../../providers/sites';
|
||||
import { CoreLocalNotificationsProvider } from '../../providers/local-notifications';
|
||||
import { CoreContentLinksHelperProvider } from '../../core/contentlinks/providers/helper';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -49,7 +53,9 @@ export class AddonMessagesModule {
|
|||
contentLinksDelegate: CoreContentLinksDelegate, indexLinkHandler: AddonMessagesIndexLinkHandler,
|
||||
discussionLinkHandler: AddonMessagesDiscussionLinkHandler, sendMessageHandler: AddonMessagesSendMessageUserHandler,
|
||||
userDelegate: CoreUserDelegate, cronDelegate: CoreCronDelegate, syncHandler: AddonMessagesSyncCronHandler,
|
||||
network: Network, messagesSync: AddonMessagesSyncProvider) {
|
||||
network: Network, messagesSync: AddonMessagesSyncProvider, appProvider: CoreAppProvider,
|
||||
localNotifications: CoreLocalNotificationsProvider, messagesProvider: AddonMessagesProvider,
|
||||
sitesProvider: CoreSitesProvider, linkHelper: CoreContentLinksHelperProvider) {
|
||||
// Register handlers.
|
||||
mainMenuDelegate.registerHandler(mainmenuHandler);
|
||||
contentLinksDelegate.registerHandler(indexLinkHandler);
|
||||
|
@ -62,5 +68,25 @@ export class AddonMessagesModule {
|
|||
network.onConnect().subscribe(() => {
|
||||
messagesSync.syncAllDiscussions(undefined, true);
|
||||
});
|
||||
|
||||
const notificationClicked = (notification: any): void => {
|
||||
messagesProvider.isMessagingEnabledForSite(notification.site).then(() => {
|
||||
sitesProvider.isFeatureDisabled('$mmSideMenuDelegate_mmaMessages', notification.site).then((disabled) => {
|
||||
if (disabled) {
|
||||
// Messages are disabled, stop.
|
||||
return;
|
||||
}
|
||||
|
||||
messagesProvider.invalidateDiscussionsCache().finally(() => {
|
||||
linkHelper.goInSite(undefined, 'AddonMessagesIndexPage', undefined, notification.site);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (appProvider.isDesktop()) {
|
||||
// Listen for clicks in simulated push notifications.
|
||||
localNotifications.registerClick(AddonMessagesProvider.PUSH_SIMULATION_COMPONENT, notificationClicked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Inject } from '@angular/core';
|
||||
import { AddonMessagesProvider } from './messages';
|
||||
import { CoreMainMenuDelegate, CoreMainMenuHandler, CoreMainMenuHandlerToDisplay } from '@core/mainmenu/providers/delegate';
|
||||
import { CoreCronHandler } from '@providers/cron';
|
||||
|
@ -21,6 +21,7 @@ import { CoreEventsProvider } from '@providers/events';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||
import { AddonPushNotificationsProvider } from '@addon/pushnotifications/providers/pushnotifications';
|
||||
|
||||
/**
|
||||
* Handler to inject an option into main menu.
|
||||
|
@ -34,7 +35,8 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr
|
|||
|
||||
constructor(private messagesProvider: AddonMessagesProvider, private sitesProvider: CoreSitesProvider,
|
||||
private eventsProvider: CoreEventsProvider, private appProvider: CoreAppProvider,
|
||||
private localNotificationsProvider: CoreLocalNotificationsProvider, private textUtils: CoreTextUtilsProvider) {
|
||||
private localNotificationsProvider: CoreLocalNotificationsProvider, private textUtils: CoreTextUtilsProvider,
|
||||
private pushNotificationsProvider: AddonPushNotificationsProvider) {
|
||||
|
||||
eventsProvider.on(AddonMessagesProvider.READ_CHANGED_EVENT, (data) => {
|
||||
this.updateBadge(data.siteId);
|
||||
|
|
|
@ -33,6 +33,7 @@ export class AddonMessagesProvider {
|
|||
static READ_CRON_EVENT = 'read_cron_event';
|
||||
static SPLIT_VIEW_LOAD_EVENT = 'split_view_load_event';
|
||||
static POLL_INTERVAL = 10000;
|
||||
static PUSH_SIMULATION_COMPONENT = 'AddonMessagesPushSimulation';
|
||||
|
||||
protected logger;
|
||||
|
||||
|
@ -521,7 +522,7 @@ export class AddonMessagesProvider {
|
|||
* @since 3.2
|
||||
*/
|
||||
isMarkAllMessagesReadEnabled(): boolean {
|
||||
return this.sitesProvider.getCurrentSite().wsAvailable('core_message_mark_all_messages_as_read');
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_message_mark_all_messages_as_read');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -531,7 +532,25 @@ export class AddonMessagesProvider {
|
|||
* @since 3.2
|
||||
*/
|
||||
isMessageCountEnabled(): boolean {
|
||||
return this.sitesProvider.getCurrentSite().wsAvailable('core_message_get_unread_conversations_count');
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_message_get_unread_conversations_count');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not messaging is enabled for a certain site.
|
||||
*
|
||||
* This could call a WS so do not abuse this method.
|
||||
*
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Resolved when enabled, otherwise rejected.
|
||||
*/
|
||||
isMessagingEnabledForSite(siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
if (!site.canUseAdvancedFeature('messaging')) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -553,7 +572,7 @@ export class AddonMessagesProvider {
|
|||
* @since 3.2
|
||||
*/
|
||||
isSearchMessagesEnabled(): boolean {
|
||||
return this.sitesProvider.getCurrentSite().wsAvailable('core_message_data_for_messagearea_search_messages');
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_message_data_for_messagearea_search_messages');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { CoreLoggerProvider } from '../../../providers/logger';
|
||||
|
||||
/**
|
||||
* Service to handle push notifications clicks.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonPushNotificationsDelegate {
|
||||
|
||||
protected logger;
|
||||
protected clickHandlers: { [s: string]: Function } = {};
|
||||
protected receiveHandlers: { [s: string]: Function } = {};
|
||||
protected counterHandlers: { [s: string]: string } = {};
|
||||
|
||||
constructor(loggerProvider: CoreLoggerProvider) {
|
||||
this.logger = loggerProvider.getInstance('AddonPushNotificationsDelegate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when a push notification is clicked. Sends notification to handlers.
|
||||
*
|
||||
* @param {any} notification Notification clicked.
|
||||
*/
|
||||
clicked(notification: any): void {
|
||||
for (const name in this.clickHandlers) {
|
||||
const callback = this.clickHandlers[name];
|
||||
if (typeof callback == 'function') {
|
||||
const treated = callback(notification);
|
||||
if (treated) {
|
||||
return; // Stop execution when notification is treated.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when a push notification is received in foreground (cannot tell when it's received in background).
|
||||
* Sends notification to all handlers.
|
||||
*
|
||||
* @param {any} notification Notification received.
|
||||
*/
|
||||
received(notification: any): void {
|
||||
for (const name in this.receiveHandlers) {
|
||||
const callback = this.receiveHandlers[name];
|
||||
if (typeof callback == 'function') {
|
||||
callback(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a push notifications handler for CLICKS.
|
||||
* When a notification is clicked, the handler will receive a notification to treat.
|
||||
*
|
||||
* @param {string} name Handler's name.
|
||||
* @param {Function} callback The callback function. Will get as parameter the clicked notification.
|
||||
* @description
|
||||
* The handler should return true if the notification is the one expected, false otherwise.
|
||||
* @see {@link AddonPushNotificationsDelegate#clicked}
|
||||
*/
|
||||
registerHandler(name: string, callback: Function): void {
|
||||
this.logger.debug(`Registered handler '${name}' as CLICK push notification handler.`);
|
||||
this.clickHandlers[name] = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a push notifications handler for RECEIVE notifications in foreground (cannot tell when it's received in background).
|
||||
* When a notification is received, the handler will receive a notification to treat.
|
||||
*
|
||||
* @param {string} name Handler's name.
|
||||
* @param {Function} callback The callback function. Will get as parameter the clicked notification.
|
||||
* @see {@link AddonPushNotificationsDelegate#received}
|
||||
*/
|
||||
registerReceiveHandler(name: string, callback: Function): void {
|
||||
this.logger.debug(`Registered handler '${name}' as RECEIVE push notification handler.`);
|
||||
this.receiveHandlers[name] = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a push notifications handler for RECEIVE notifications.
|
||||
*
|
||||
* @param {string} name Handler's name.
|
||||
*/
|
||||
unregisterReceiveHandler(name: string): void {
|
||||
this.logger.debug(`Unregister handler '${name}' from RECEIVE push notification handlers.`);
|
||||
delete this.receiveHandlers[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a push notifications handler for update badge counter.
|
||||
*
|
||||
* @param {string} name Handler's name.
|
||||
*/
|
||||
registerCounterHandler(name: string): void {
|
||||
this.logger.debug(`Registered handler '${name}' as badge counter handler.`);
|
||||
this.counterHandlers[name] = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a counter handler is present.
|
||||
*
|
||||
* @param {string} name Handler's name.
|
||||
* @return {boolean} If handler name is present.
|
||||
*/
|
||||
isCounterHandlerRegistered(name: string): boolean {
|
||||
return typeof this.counterHandlers[name] != 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all counter badge handlers.
|
||||
*
|
||||
* @return {any} with all the handler names.
|
||||
*/
|
||||
getCounterHandlers(): any {
|
||||
return this.counterHandlers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { Platform } from 'ionic-angular';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { AddonPushNotificationsDelegate } from './delegate';
|
||||
|
||||
/**
|
||||
* Service to handle push notifications.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonPushNotificationsProvider {
|
||||
|
||||
protected logger;
|
||||
protected pushID: string;
|
||||
protected appDB: any;
|
||||
|
||||
// Variables for database.
|
||||
protected BADGE_TABLE = 'mma_pushnotifications_badge';
|
||||
protected tablesSchema = [
|
||||
{
|
||||
name: this.BADGE_TABLE,
|
||||
columns: [
|
||||
{
|
||||
name: 'siteid',
|
||||
type: 'INTEGER'
|
||||
},
|
||||
{
|
||||
name: 'addon',
|
||||
type: 'TEXT'
|
||||
},
|
||||
{
|
||||
name: 'number',
|
||||
type: 'INTEGER'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
constructor(logger: CoreLoggerProvider, protected appProvider: CoreAppProvider, private platform: Platform,
|
||||
protected pushNotificationsDelegate: AddonPushNotificationsDelegate, protected sitesProvider: CoreSitesProvider) {
|
||||
this.logger = logger.getInstance('AddonPushNotificationsProvider');
|
||||
this.appDB = appProvider.getDB();
|
||||
this.appDB.createTablesFromSchema(this.tablesSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pushID for this device.
|
||||
*
|
||||
* @return {string} Push ID.
|
||||
*/
|
||||
getPushId(): string {
|
||||
return this.pushID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when a push notification is clicked. Redirect the user to the right state.
|
||||
*
|
||||
* @param {any} notification Notification.
|
||||
*/
|
||||
notificationClicked(notification: any): void {
|
||||
this.platform.ready().then(() => {
|
||||
this.pushNotificationsDelegate.clicked(notification);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { AddonPushNotificationsProvider } from './providers/pushnotifications';
|
||||
import { AddonPushNotificationsDelegate } from './providers/delegate';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
],
|
||||
providers: [
|
||||
AddonPushNotificationsProvider,
|
||||
AddonPushNotificationsDelegate
|
||||
]
|
||||
})
|
||||
export class AddonPushNotificationsModule {
|
||||
constructor() {}
|
||||
}
|
|
@ -16,10 +16,10 @@ import { Component, OnInit } from '@angular/core';
|
|||
import { Platform } from 'ionic-angular';
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
import { CoreAppProvider } from '../providers/app';
|
||||
import { CoreEventsProvider } from '../providers/events';
|
||||
import { CoreLoggerProvider } from '../providers/logger';
|
||||
import { CoreLoginHelperProvider } from '../core/login/providers/helper';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'app.html'
|
||||
|
|
|
@ -71,6 +71,7 @@ import { AddonFilesModule } from '@addon/files/files.module';
|
|||
import { AddonModBookModule } from '@addon/mod/book/book.module';
|
||||
import { AddonModLabelModule } from '@addon/mod/label/label.module';
|
||||
import { AddonMessagesModule } from '@addon/messages/messages.module';
|
||||
import { AddonPushNotificationsModule } from '@addon/pushnotifications/pushnotifications.module';
|
||||
|
||||
// For translate loader. AoT requires an exported function for factories.
|
||||
export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
||||
|
@ -113,7 +114,8 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader {
|
|||
AddonFilesModule,
|
||||
AddonModBookModule,
|
||||
AddonModLabelModule,
|
||||
AddonMessagesModule
|
||||
AddonMessagesModule,
|
||||
AddonPushNotificationsModule
|
||||
],
|
||||
bootstrap: [IonicApp],
|
||||
entryComponents: [
|
||||
|
|
|
@ -238,7 +238,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
|
|||
* @return {boolean} True if can check updates, false otherwise.
|
||||
*/
|
||||
canCheckUpdates(): boolean {
|
||||
return this.sitesProvider.getCurrentSite().wsAvailable('core_course_check_updates');
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_course_check_updates');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -355,7 +355,7 @@ export class CoreCoursesProvider {
|
|||
* @return {boolean} Whether get courses by field is available.
|
||||
*/
|
||||
isGetCoursesByFieldAvailable(): boolean {
|
||||
return this.sitesProvider.getCurrentSite().wsAvailable('core_course_get_courses_by_field');
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_course_get_courses_by_field');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,8 +16,10 @@ import { NgModule } from '@angular/core';
|
|||
import { Platform } from 'ionic-angular';
|
||||
|
||||
// Ionic Native services.
|
||||
import { Badge } from '@ionic-native/badge';
|
||||
import { Camera } from '@ionic-native/camera';
|
||||
import { Clipboard } from '@ionic-native/clipboard';
|
||||
import { Device } from '@ionic-native/device';
|
||||
import { File } from '@ionic-native/file';
|
||||
import { FileTransfer } from '@ionic-native/file-transfer';
|
||||
import { Globalization } from '@ionic-native/globalization';
|
||||
|
@ -26,6 +28,7 @@ import { Keyboard } from '@ionic-native/keyboard';
|
|||
import { LocalNotifications } from '@ionic-native/local-notifications';
|
||||
import { MediaCapture } from '@ionic-native/media-capture';
|
||||
import { Network } from '@ionic-native/network';
|
||||
import { Push } from '@ionic-native/push';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen';
|
||||
import { StatusBar } from '@ionic-native/status-bar';
|
||||
import { SQLite } from '@ionic-native/sqlite';
|
||||
|
@ -68,6 +71,7 @@ import { CoreInitDelegate } from '../../providers/init';
|
|||
imports: [
|
||||
],
|
||||
providers: [
|
||||
Badge,
|
||||
CoreEmulatorHelperProvider,
|
||||
CoreEmulatorCaptureHelperProvider,
|
||||
{
|
||||
|
@ -84,6 +88,7 @@ import { CoreInitDelegate } from '../../providers/init';
|
|||
return appProvider.isMobile() ? new Clipboard() : new ClipboardMock(appProvider);
|
||||
}
|
||||
},
|
||||
Device,
|
||||
{
|
||||
provide: File,
|
||||
deps: [CoreAppProvider, CoreTextUtilsProvider],
|
||||
|
@ -139,6 +144,7 @@ import { CoreInitDelegate } from '../../providers/init';
|
|||
return platform.is('cordova') ? new Network() : new NetworkMock();
|
||||
}
|
||||
},
|
||||
Push,
|
||||
SplashScreen,
|
||||
StatusBar,
|
||||
SQLite,
|
||||
|
|
|
@ -901,7 +901,7 @@ export class CoreLoginHelperProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.sitesProvider.getCurrentSite().wsAvailable('core_user_agree_site_policy')) {
|
||||
if (!this.sitesProvider.wsAvailableInCurrentSite('core_user_agree_site_policy')) {
|
||||
// WS not available, stop.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1212,4 +1212,17 @@ export class CoreSitesProvider {
|
|||
this.sites[id].getDb().createTablesFromSchema(tables);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a WS is available in the current site, if any.
|
||||
*
|
||||
* @param {string} method WS name.
|
||||
* @param {boolean} [checkPrefix=true] When true also checks with the compatibility prefix.
|
||||
* @return {boolean} Whether the WS is available.
|
||||
*/
|
||||
wsAvailableInCurrentSite(method: string, checkPrefix: boolean = true): boolean {
|
||||
const site = this.getCurrentSite();
|
||||
|
||||
return site && site.wsAvailable(method, checkPrefix);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue