MOBILE-3829 notifications: Display notification clicked in new page
parent
1ffe48c915
commit
7ee3324455
|
@ -27,6 +27,11 @@ function buildRoutes(injector: Injector): Routes {
|
|||
},
|
||||
loadChildren: () => import('./pages/list/list.module').then(m => m.AddonNotificationsListPageModule),
|
||||
},
|
||||
{
|
||||
path: 'notification',
|
||||
loadChildren: () => import('./pages/notification/notification.module')
|
||||
.then(m => m.AddonNotificationsNotificationPageModule),
|
||||
},
|
||||
...buildTabMainRoutes(injector, {
|
||||
redirectTo: 'list',
|
||||
pathMatch: 'full',
|
||||
|
|
|
@ -18,15 +18,17 @@ import { Subscription } from 'rxjs';
|
|||
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreEvents, CoreEventObserver } from '@singletons/events';
|
||||
import {
|
||||
AddonNotifications,
|
||||
AddonNotificationsNotificationMessageFormatted,
|
||||
AddonNotificationsProvider,
|
||||
} from '../../services/notifications';
|
||||
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
|
||||
import {
|
||||
AddonNotificationsHelper,
|
||||
AddonNotificationsNotificationToRender,
|
||||
} from '@addons/notifications/services/notifications-helper';
|
||||
|
||||
/**
|
||||
* Page that displays the list of notifications.
|
||||
|
@ -38,7 +40,7 @@ import { CorePushNotificationsDelegate } from '@features/pushnotifications/servi
|
|||
})
|
||||
export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
||||
|
||||
notifications: FormattedNotification[] = [];
|
||||
notifications: AddonNotificationsNotificationToRender[] = [];
|
||||
notificationsLoaded = false;
|
||||
canLoadMore = false;
|
||||
loadMoreError = false;
|
||||
|
@ -94,7 +96,8 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
|||
try {
|
||||
const result = await AddonNotifications.getNotifications(refresh ? [] : this.notifications);
|
||||
|
||||
const notifications = result.notifications.map((notification) => this.formatText(notification));
|
||||
const notifications = result.notifications
|
||||
.map((notification) => AddonNotificationsHelper.formatNotificationText(notification));
|
||||
|
||||
if (refresh) {
|
||||
this.notifications = notifications;
|
||||
|
@ -135,7 +138,7 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
|||
*
|
||||
* @param notifications Array of notification objects.
|
||||
*/
|
||||
protected async markNotificationsAsRead(notifications: FormattedNotification[]): Promise<void> {
|
||||
protected async markNotificationsAsRead(notifications: AddonNotificationsNotificationToRender[]): Promise<void> {
|
||||
if (notifications.length > 0) {
|
||||
const promises = notifications.map(async (notification) => {
|
||||
if (notification.read) {
|
||||
|
@ -194,33 +197,6 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the text of a notification.
|
||||
*
|
||||
* @param notification The notification object.
|
||||
*/
|
||||
protected formatText(notification: AddonNotificationsNotificationMessageFormatted): FormattedNotification {
|
||||
const formattedNotification: FormattedNotification = notification;
|
||||
formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification);
|
||||
formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists.
|
||||
|
||||
formattedNotification.mobiletext = formattedNotification.displayfullhtml ?
|
||||
notification.fullmessagehtml :
|
||||
CoreTextUtils.replaceNewLines((formattedNotification.mobiletext || '').replace(/-{4,}/ig, ''), '<br>');
|
||||
|
||||
return formattedNotification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we should display full HTML of the notification.
|
||||
*
|
||||
* @param notification Notification.
|
||||
* @return Whether to display full HTML.
|
||||
*/
|
||||
protected shouldDisplayFullHtml(notification: FormattedNotification): boolean {
|
||||
return notification.component == 'mod_forum' && notification.eventtype == 'digests';
|
||||
}
|
||||
|
||||
/**
|
||||
* User entered the page.
|
||||
*/
|
||||
|
@ -253,8 +229,3 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
type FormattedNotification = AddonNotificationsNotificationMessageFormatted & {
|
||||
displayfullhtml?: boolean; // Whether to display the full HTML of the notification.
|
||||
iconurl?: string;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<h2>{{ 'addon.notifications.notifications' | translate }}</h2>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<ion-item class="ion-text-wrap" lines="none" [attr.aria-label]="subject">
|
||||
<core-user-avatar *ngIf="userIdFrom > 0" slot="start" [userId]="userIdFrom" [profileUrl]="profileImageUrlFrom"
|
||||
[fullname]="userFromFullName" [extraIcon]="iconUrl"></core-user-avatar>
|
||||
|
||||
<img *ngIf="userIdFrom <= 0 && iconUrl" [src]="iconUrl" alt=""
|
||||
role="presentation" class="core-notification-icon" slot="start">
|
||||
|
||||
<ion-label>
|
||||
<p class="item-heading">{{ subject }}</p>
|
||||
<p *ngIf="userIdFrom > 0">{{ userFromFullName }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap">
|
||||
<ion-label>
|
||||
<core-format-text [text]="content | coreCreateLinks" contextLevel="system" [contextInstanceId]="0">
|
||||
</core-format-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,40 @@
|
|||
// (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 { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { AddonNotificationsComponentsModule } from '../../components/components.module';
|
||||
import { AddonNotificationsNotificationPage } from './notification';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AddonNotificationsNotificationPage,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
CoreSharedModule,
|
||||
AddonNotificationsComponentsModule,
|
||||
],
|
||||
declarations: [
|
||||
AddonNotificationsNotificationPage,
|
||||
],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AddonNotificationsNotificationPageModule {}
|
|
@ -0,0 +1,90 @@
|
|||
// (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 { AddonNotificationsNotificationData } from '@addons/notifications/services/handlers/push-click';
|
||||
import { AddonNotifications } from '@addons/notifications/services/notifications';
|
||||
import {
|
||||
AddonNotificationsHelper,
|
||||
AddonNotificationsNotificationToRender,
|
||||
} from '@addons/notifications/services/notifications-helper';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
|
||||
/**
|
||||
* Page to render a notification.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-addon-notifications-notification',
|
||||
templateUrl: 'notification.html',
|
||||
})
|
||||
export class AddonNotificationsNotificationPage implements OnInit {
|
||||
|
||||
subject = ''; // Notification subject.
|
||||
content = ''; // Notification content.
|
||||
userIdFrom = -1; // User ID who sent the notification.
|
||||
profileImageUrlFrom?: string; // Avatar of the user who sent the notification.
|
||||
userFromFullName?: string; // Name of the user who sent the notification.
|
||||
iconUrl?: string; // Icon URL.
|
||||
loaded = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
let notification: AddonNotificationsNotificationToRender | AddonNotificationsNotificationData;
|
||||
|
||||
try {
|
||||
notification = CoreNavigator.getRequiredRouteParam('notification');
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModal(error);
|
||||
|
||||
CoreNavigator.back();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('subject' in notification)) {
|
||||
// Try to find the notification using the WebService, it contains a better message.
|
||||
const notifId = Number(notification.savedmessageid);
|
||||
const result = await CoreUtils.ignoreErrors(
|
||||
AddonNotifications.getNotifications([], { siteId: notification.site }),
|
||||
);
|
||||
|
||||
const foundNotification = result?.notifications.find(notif => notif.id === notifId);
|
||||
if (foundNotification) {
|
||||
notification = AddonNotificationsHelper.formatNotificationText(foundNotification);
|
||||
}
|
||||
}
|
||||
|
||||
if ('subject' in notification) {
|
||||
this.subject = notification.subject;
|
||||
this.content = notification.mobiletext || notification.fullmessagehtml;
|
||||
this.userIdFrom = notification.useridfrom;
|
||||
this.profileImageUrlFrom = notification.profileimageurlfrom;
|
||||
this.userFromFullName = notification.userfromfullname;
|
||||
this.iconUrl = notification.iconurl;
|
||||
} else {
|
||||
this.subject = notification.title || '';
|
||||
this.content = notification.message || '';
|
||||
this.userIdFrom = notification.userfromid ? Number(notification.userfromid) : -1;
|
||||
this.profileImageUrlFrom = notification.senderImage;
|
||||
this.userFromFullName = notification.userfromfullname;
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -127,10 +127,16 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
|
|||
await CoreUtils.ignoreErrors(AddonNotifications.invalidateNotificationsList(notification.site));
|
||||
|
||||
await CoreNavigator.navigateToSitePath(
|
||||
AddonNotificationsMainMenuHandlerService.PAGE_NAME,
|
||||
`${AddonNotificationsMainMenuHandlerService.PAGE_NAME}/list`,
|
||||
{
|
||||
siteId: notification.site,
|
||||
preferCurrentTab: false,
|
||||
nextNavigation: {
|
||||
path: '../notification',
|
||||
options: {
|
||||
params: { notification },
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -139,7 +145,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
|
|||
|
||||
export const AddonNotificationsPushClickHandler = makeSingleton(AddonNotificationsPushClickHandlerService);
|
||||
|
||||
type AddonNotificationsNotificationData = CorePushNotificationsNotificationBasicData & {
|
||||
export type AddonNotificationsNotificationData = CorePushNotificationsNotificationBasicData & {
|
||||
contexturl?: string; // URL related to the notification.
|
||||
savedmessageid?: number; // Notification ID (optional).
|
||||
id?: number; // Notification ID (optional).
|
||||
|
|
|
@ -18,12 +18,14 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { makeSingleton } from '@singletons';
|
||||
import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate';
|
||||
import {
|
||||
AddonNotificationsNotificationMessageFormatted,
|
||||
AddonNotificationsPreferences,
|
||||
AddonNotificationsPreferencesComponent,
|
||||
AddonNotificationsPreferencesNotification,
|
||||
AddonNotificationsPreferencesNotificationProcessor,
|
||||
AddonNotificationsPreferencesProcessor,
|
||||
} from './notifications';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
|
||||
/**
|
||||
* Service that provides some helper functions for notifications.
|
||||
|
@ -31,6 +33,25 @@ import {
|
|||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonNotificationsHelperProvider {
|
||||
|
||||
/**
|
||||
* Formats the text of a notification.
|
||||
*
|
||||
* @param notification The notification object.
|
||||
*/
|
||||
formatNotificationText(
|
||||
notification: AddonNotificationsNotificationMessageFormatted,
|
||||
): AddonNotificationsNotificationToRender {
|
||||
const formattedNotification: AddonNotificationsNotificationToRender = notification;
|
||||
formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification);
|
||||
formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists.
|
||||
|
||||
formattedNotification.mobiletext = formattedNotification.displayfullhtml ?
|
||||
notification.fullmessagehtml :
|
||||
CoreTextUtils.replaceNewLines((formattedNotification.mobiletext || '').replace(/-{4,}/ig, ''), '<br>');
|
||||
|
||||
return formattedNotification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format preferences data.
|
||||
*
|
||||
|
@ -119,6 +140,16 @@ export class AddonNotificationsHelperProvider {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we should display full HTML of the notification.
|
||||
*
|
||||
* @param notification Notification.
|
||||
* @return Whether to display full HTML.
|
||||
*/
|
||||
protected shouldDisplayFullHtml(notification: AddonNotificationsNotificationToRender): boolean {
|
||||
return notification.component == 'mod_forum' && notification.eventtype == 'digests';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const AddonNotificationsHelper = makeSingleton(AddonNotificationsHelperProvider);
|
||||
|
@ -151,3 +182,11 @@ export type AddonNotificationsPreferencesNotificationFormatted = AddonNotificati
|
|||
export type AddonNotificationsPreferencesProcessorFormatted = AddonNotificationsPreferencesProcessor & {
|
||||
supported?: boolean; // Calculated in the app. Whether the processor is supported in the app.
|
||||
};
|
||||
|
||||
/**
|
||||
* Notification with some calculated data to render it.
|
||||
*/
|
||||
export type AddonNotificationsNotificationToRender = AddonNotificationsNotificationMessageFormatted & {
|
||||
displayfullhtml?: boolean; // Whether to display the full HTML of the notification.
|
||||
iconurl?: string;
|
||||
};
|
||||
|
|
|
@ -209,7 +209,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy {
|
|||
|
||||
// Go to the site initial page.
|
||||
this.page
|
||||
? await CoreNavigator.navigateToSitePath(this.page, { params: this.pageOptions })
|
||||
? await CoreNavigator.navigateToSitePath(this.page, this.pageOptions)
|
||||
: await CoreNavigator.navigateToSiteHome();
|
||||
} catch (error) {
|
||||
CoreLoginHelper.treatUserTokenError(this.siteUrl, error, this.username, password);
|
||||
|
|
Loading…
Reference in New Issue