Merge pull request #1661 from albertgasset/MOBILE-2734

Mobile 2734
main
Juan Leyva 2018-12-14 13:17:59 +01:00 committed by GitHub
commit 377cf800ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 331 additions and 154 deletions

View File

@ -55,6 +55,8 @@ export class AddonMessagesConfirmedContactsComponent implements OnInit, OnDestro
if (index >= 0) {
this.contacts.splice(index, 1);
}
} else if (data.contactRequestConfirmed) {
this.refreshData();
}
}, sitesProvider.getCurrentSiteId());
}

View File

@ -53,7 +53,7 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
constructor(private eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, translate: TranslateService,
private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams,
private appProvider: CoreAppProvider, platform: Platform, utils: CoreUtilsProvider,
private appProvider: CoreAppProvider, platform: Platform, private utils: CoreUtilsProvider,
pushNotificationsDelegate: AddonPushNotificationsDelegate) {
this.search.loading = translate.instant('core.searching');
@ -91,17 +91,13 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
// A discussion has been read reset counter.
discussion.unread = false;
// Discussions changed, invalidate them.
this.messagesProvider.invalidateDiscussionsCache();
// Conversations changed, invalidate them and refresh unread counts.
this.messagesProvider.invalidateConversations();
this.messagesProvider.refreshUnreadConversationCounts();
}
}
}, this.siteId);
// Update discussions when cron read is executed.
this.cronObserver = eventsProvider.on(AddonMessagesProvider.READ_CRON_EVENT, (data) => {
this.refreshData();
}, this.siteId);
// Refresh the view when the app is resumed.
this.appResumeSubscription = platform.resume.subscribe(() => {
if (!this.loaded) {
@ -117,7 +113,8 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
this.pushObserver = pushNotificationsDelegate.on('receive').subscribe((notification) => {
// New message received. If it's from current site, refresh the data.
if (utils.isFalseOrZero(notification.notif) && notification.site == this.siteId) {
this.refreshData();
// Don't refresh unread counts, it's refreshed from the main menu handler in this case.
this.refreshData(null, false);
}
});
}
@ -143,14 +140,20 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
* Refresh the data.
*
* @param {any} [refresher] Refresher.
* @param {boolean} [refreshUnreadCounts=true] Whteher to refresh unread counts.
* @return {Promise<any>} Promise resolved when done.
*/
refreshData(refresher?: any): Promise<any> {
return this.messagesProvider.invalidateDiscussionsCache().then(() => {
refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise<any> {
const promises = [];
promises.push(this.messagesProvider.invalidateDiscussionsCache());
if (refreshUnreadCounts) {
promises.push(this.messagesProvider.invalidateUnreadConversationCounts());
}
return this.utils.allPromises(promises).finally(() => {
return this.fetchData().finally(() => {
if (refresher) {
// Actions to take if refresh comes from the user.
this.eventsProvider.trigger(AddonMessagesProvider.READ_CHANGED_EVENT, undefined, this.siteId);
refresher.complete();
}
});
@ -166,7 +169,9 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
this.loadingMessage = this.loadingMessages;
this.search.enabled = this.messagesProvider.isSearchMessagesEnabled();
return this.messagesProvider.getDiscussions().then((discussions) => {
const promises = [];
promises.push(this.messagesProvider.getDiscussions().then((discussions) => {
// Convert to an array for sorting.
const discussionsSorted = [];
for (const userId in discussions) {
@ -177,7 +182,11 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
this.discussions = discussionsSorted.sort((a, b) => {
return b.message.timecreated - a.message.timecreated;
});
}).catch((error) => {
}));
promises.push(this.messagesProvider.getUnreadConversationCounts());
return Promise.all(promises).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true);
}).finally(() => {
this.loaded = true;

View File

@ -107,7 +107,11 @@ export class AddonMessagesModule {
}
messagesProvider.invalidateDiscussionsCache(notification.site).finally(() => {
linkHelper.goInSite(undefined, 'AddonMessagesIndexPage', undefined, notification.site);
let pageName = 'AddonMessagesIndexPage';
if (messagesProvider.isGroupMessagingEnabled()) {
pageName = 'AddonMessagesGroupConversationsPage';
}
linkHelper.goInSite(undefined, pageName, undefined, notification.site);
});
});
});

View File

@ -93,7 +93,7 @@ export class AddonMessagesContactsPage implements OnDestroy {
selectUser(tab: string, userId?: number, onInit: boolean = false): void {
userId = userId || this.selectedUserId[tab];
if (!userId || userId == this.conversationUserId) {
if (!userId || userId == this.conversationUserId && this.splitviewCtrl.isOn()) {
// No user conversation to open or it is already opened.
return;
}

View File

@ -205,7 +205,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
// Synchronize messages if needed.
return this.messagesSync.syncDiscussion(this.conversationId, this.userId).catch(() => {
// Ignore errors.
}).then((warnings) => {
}).then((warnings): Promise<any> => {
if (warnings && warnings[0]) {
this.domUtils.showErrorModal(warnings[0]);
}
@ -213,22 +213,26 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
if (this.groupMessagingEnabled) {
// Get the conversation ID if it exists and we don't have it yet.
return this.getConversation(this.conversationId, this.userId).then((exists) => {
const promises = [];
if (exists) {
// Fetch the messages for the first time.
return this.fetchMessages();
}
}).then(() => {
let promise;
if (this.userId) {
promise = this.messagesProvider.getMemberInfo(this.userId);
} else {
// Group conversation.
promise = Promise.resolve(null);
promises.push(this.fetchMessages());
}
return promise.then((member) => {
if (this.userId) {
promises.push(this.messagesProvider.getMemberInfo(this.userId).then((member) => {
this.otherMember = member;
});
if (!exists && member) {
this.conversationImage = member.profileimageurl;
this.title = member.fullname;
}
}));
} else {
this.otherMember = null;
}
return Promise.all(promises);
});
} else {
this.otherMember = null;

View File

@ -31,7 +31,7 @@
<core-icon *ngIf="!favourites.expanded" name="fa-caret-right" item-start></core-icon>
<core-icon *ngIf="favourites.expanded" name="fa-caret-down" item-start></core-icon>
{{ 'core.favourites' | translate }} ({{ favourites.count }})
<!-- @todo: Unread total of favourites (MDL-63913). -->
<ion-badge item-end *ngIf="favourites.unread">{{ favourites.unread }}</ion-badge>
</ion-item-divider>
<div *ngIf="favourites.conversations && favourites.expanded">
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}"></ng-container>
@ -47,7 +47,7 @@
<core-icon *ngIf="!group.expanded" name="fa-caret-right" item-start></core-icon>
<core-icon *ngIf="group.expanded" name="fa-caret-down" item-start></core-icon>
{{ 'addon.messages.groupmessages' | translate }} ({{ group.count }})
<!-- @todo: Unread total of group conversations (MDL-63913). -->
<ion-badge item-end *ngIf="group.unread">{{ group.unread }}</ion-badge>
</ion-item-divider>
<div *ngIf="group.conversations && group.expanded">
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}"></ng-container>
@ -62,7 +62,7 @@
<core-icon *ngIf="!individual.expanded" name="fa-caret-right" item-start></core-icon>
<core-icon *ngIf="individual.expanded" name="fa-caret-down" item-start></core-icon>
{{ 'addon.messages.messages' | translate }} ({{ individual.count }})
<!-- @todo: Unread total of individual conversations (MDL-63913). -->
<ion-badge item-end *ngIf="individual.unread">{{ individual.unread }}</ion-badge>
</ion-item-divider>
<div *ngIf="individual.conversations && individual.expanded">
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}"></ng-container>

View File

@ -44,15 +44,21 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
contactRequestsCount = 0;
favourites: any = {
type: null,
favourites: true
favourites: true,
count: 0,
unread: 0
};
group: any = {
type: AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP,
favourites: false
favourites: false,
count: 0,
unread: 0
};
individual: any = {
type: AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
favourites: false
favourites: false,
count: 0,
unread: 0
};
typeIndividual = AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
@ -70,9 +76,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
protected contactRequestsCountObserver: any;
protected memberInfoObserver: any;
constructor(private eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, translate: TranslateService,
constructor(eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, translate: TranslateService,
private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams,
private navCtrl: NavController, platform: Platform, utils: CoreUtilsProvider,
private navCtrl: NavController, platform: Platform, private utils: CoreUtilsProvider,
pushNotificationsDelegate: AddonPushNotificationsDelegate, private messagesOffline: AddonMessagesOfflineProvider,
private userProvider: CoreUserProvider) {
@ -119,17 +125,13 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
// A conversation has been read reset counter.
conversation.unreadcount = 0;
// Conversations changed, invalidate them.
// Conversations changed, invalidate them and refresh unread counts.
this.messagesProvider.invalidateConversations();
this.messagesProvider.refreshUnreadConversationCounts();
}
}
}, this.siteId);
// Update conversations when cron read is executed.
this.cronObserver = eventsProvider.on(AddonMessagesProvider.READ_CRON_EVENT, (data) => {
this.refreshData();
}, this.siteId);
// Load a discussion if we receive an event to do so.
this.openConversationObserver = eventsProvider.on(AddonMessagesProvider.OPEN_CONVERSATION_EVENT, (data) => {
if (data.conversationId || data.userId) {
@ -157,10 +159,18 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
this.pushObserver = pushNotificationsDelegate.on('receive').subscribe((notification) => {
// New message received. If it's from current site, refresh the data.
if (utils.isFalseOrZero(notification.notif) && notification.site == this.siteId) {
this.refreshData();
// Don't refresh unread counts, it's refreshed from the main menu handler in this case.
this.refreshData(null, false);
}
});
// Update unread conversation counts.
this.cronObserver = eventsProvider.on(AddonMessagesProvider.UNREAD_CONVERSATION_COUNTS_EVENT, (data) => {
this.favourites.unread = data.favourites;
this.individual.unread = data.individual;
this.group.unread = data.group;
}, this.siteId);
// Update the contact requests badge.
this.contactRequestsCountObserver = eventsProvider.on(AddonMessagesProvider.CONTACT_REQUESTS_COUNT_EVENT, (data) => {
this.contactRequestsCount = data.count;
@ -215,8 +225,6 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
}
}
});
this.messagesProvider.getContactRequestsCount(this.siteId); // Badge is updated by the observer.
}
/**
@ -234,6 +242,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
promises.push(this.fetchDataForOption(this.favourites, false));
promises.push(this.fetchDataForOption(this.group, false));
promises.push(this.fetchDataForOption(this.individual, false));
promises.push(this.fetchConversationCounts());
promises.push(this.messagesProvider.getUnreadConversationCounts()); // View updated by the event observer.
promises.push(this.messagesProvider.getContactRequestsCount()); // View updated by the event observer.
promises.push(this.messagesOffline.getAllMessages().then((messages) => {
offlineMessages = messages;
}));
@ -289,7 +300,6 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
if (loadingMore) {
option.conversations = option.conversations.concat(data.conversations);
} else {
option.count = data.canLoadMore ? AddonMessagesProvider.LIMIT_MESSAGES + '+' : data.conversations.length;
option.conversations = data.conversations;
}
@ -298,6 +308,19 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
});
}
/**
* Fetch conversation counts.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchConversationCounts(): Promise<void> {
return this.messagesProvider.getConversationCounts().then((counts) => {
this.favourites.count = counts.favourites;
this.individual.count = counts.individual;
this.group.count = counts.group;
});
}
/**
* Find a conversation in the list of loaded conversations.
*
@ -494,15 +517,23 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
* Refresh the data.
*
* @param {any} [refresher] Refresher.
* @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts.
* @return {Promise<any>} Promise resolved when done.
*/
refreshData(refresher?: any): Promise<any> {
return this.messagesProvider.invalidateConversations().then(() => {
refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise<any> {
const promises = [
this.messagesProvider.invalidateConversations(),
this.messagesProvider.invalidateConversationCounts(),
this.messagesProvider.invalidateContactRequestsCountCache()
];
if (refreshUnreadCounts) {
promises.push(this.messagesProvider.invalidateUnreadConversationCounts());
}
return this.utils.allPromises(promises).finally(() => {
return this.fetchData().finally(() => {
if (refresher) {
// Actions to take if refresh comes from the user.
this.eventsProvider.trigger(AddonMessagesProvider.READ_CHANGED_EVENT, undefined, this.siteId);
this.messagesProvider.refreshContactRequestsCount(this.siteId);
refresher.complete();
}
});

View File

@ -1,7 +1,10 @@
<ion-header>
<ion-navbar core-back-button>
<ion-title>{{ 'addon.messages.messages' | translate }}</ion-title>
<ion-buttons end></ion-buttons>
<ion-buttons end>
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu disappears in some cases. -->
<core-context-menu></core-context-menu>
</ion-buttons>
</ion-navbar>
</ion-header>
<core-split-view>

View File

@ -30,7 +30,7 @@
</ion-item>
<!-- List of results -->
<a ion-item text-wrap *ngFor="let result of item.results" [title]="result.fullname" (click)="openDiscussion(result.id)" [class.core-split-item-selected]="result.id == selectedUserId" class="addon-message-discussion">
<a ion-item text-wrap *ngFor="let result of item.results" [title]="result.fullname" (click)="openConversation(result)" [class.core-split-item-selected]="result == selectedResult" class="addon-message-discussion">
<ion-avatar item-start core-user-avatar [user]="result" [checkOnline]="true" [linkProfile]="false"></ion-avatar>
<h2>
<core-format-text [text]="result.fullname"></core-format-text>

View File

@ -60,7 +60,7 @@ export class AddonMessagesSearchPage implements OnDestroy {
loadingMore: false,
loadMoreError: false
};
selectedUserId = null;
selectedResult = null;
protected memberInfoObserver;
@ -193,11 +193,11 @@ export class AddonMessagesSearchPage implements OnDestroy {
if (!loadMore) {
if (this.contacts.results.length > 0) {
this.openDiscussion(this.contacts.results[0].id, true);
this.openConversation(this.contacts.results[0], true);
} else if (this.nonContacts.results.length > 0) {
this.openDiscussion(this.nonContacts.results[0].id, true);
this.openConversation(this.nonContacts.results[0], true);
} else if (this.messages.results.length > 0) {
this.openDiscussion(this.messages.results[0].userid, true);
this.openConversation(this.messages.results[0], true);
}
}
}).catch((error) => {
@ -223,15 +223,21 @@ export class AddonMessagesSearchPage implements OnDestroy {
}
/**
* Open a discussion in the split view.
* Open a conversation in the split view.
*
* @param {number} userId User id.
* @param {any} result User or message.
* @param {boolean} [onInit=false] Whether the tser was selected on initial load.
*/
openDiscussion(userId: number, onInit: boolean = false): void {
openConversation(result: any, onInit: boolean = false): void {
if (!onInit || this.splitviewCtrl.isOn()) {
this.selectedUserId = userId;
this.splitviewCtrl.push('AddonMessagesDiscussionPage', { userId });
this.selectedResult = result;
const params: any = {};
if (result.conversationid) {
params.conversationId = result.conversationid;
} else {
params.userId = result.id;
}
this.splitviewCtrl.push('AddonMessagesDiscussionPage', params);
}
}

View File

@ -44,8 +44,13 @@ export class AddonMessagesIndexLinkHandler extends CoreContentLinksHandlerBase {
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [{
action: (siteId, navCtrl?): void => {
let pageName = 'AddonMessagesIndexPage';
if (this.messagesProvider.isGroupMessagingEnabled()) {
pageName = 'AddonMessagesGroupConversationsPage';
}
// Always use redirect to make it the new history root (to avoid "loops" in history).
this.linkHelper.goInSite(navCtrl, 'AddonMessagesIndexPage', undefined, siteId);
this.linkHelper.goInSite(navCtrl, pageName, undefined, siteId);
}
}];
}

View File

@ -43,38 +43,41 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr
loading: true
};
protected updating = false;
protected unreadCount = 0;
protected contactRequestsCount = 0;
protected orMore = false;
constructor(private messagesProvider: AddonMessagesProvider, private sitesProvider: CoreSitesProvider,
private eventsProvider: CoreEventsProvider, private appProvider: CoreAppProvider,
eventsProvider: CoreEventsProvider, private appProvider: CoreAppProvider,
private localNotificationsProvider: CoreLocalNotificationsProvider, private textUtils: CoreTextUtilsProvider,
private pushNotificationsProvider: AddonPushNotificationsProvider, utils: CoreUtilsProvider,
pushNotificationsDelegate: AddonPushNotificationsDelegate, private emulatorHelper: CoreEmulatorHelperProvider) {
eventsProvider.on(AddonMessagesProvider.READ_CHANGED_EVENT, (data) => {
this.updateBadge(data.siteId);
});
eventsProvider.on(AddonMessagesProvider.READ_CRON_EVENT, (data) => {
eventsProvider.on(AddonMessagesProvider.UNREAD_CONVERSATION_COUNTS_EVENT, (data) => {
this.unreadCount = data.favourites + data.individual + data.group;
this.orMore = data.orMore;
this.updateBadge(data.siteId);
});
eventsProvider.on(AddonMessagesProvider.CONTACT_REQUESTS_COUNT_EVENT, (data) => {
this.updateBadge(data.siteId, data.count);
this.contactRequestsCount = data.count;
this.updateBadge(data.siteId);
});
// Reset info on logout.
eventsProvider.on(CoreEventsProvider.LOGOUT, (data) => {
this.unreadCount = 0;
this.contactRequestsCount = 0;
this.orMore = false;
this.handler.badge = '';
this.handler.loading = true;
this.updating = false;
});
// If a message push notification is received, refresh the count.
pushNotificationsDelegate.on('receive').subscribe((notification) => {
// New message received. If it's from current site, refresh the data.
if (utils.isFalseOrZero(notification.notif) && this.sitesProvider.isCurrentSite(notification.site)) {
this.updateBadge(notification.site);
this.refreshBadge(notification.site);
}
});
@ -101,65 +104,60 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr
'AddonMessagesGroupConversationsPage' : 'AddonMessagesIndexPage';
if (this.handler.loading) {
this.updateBadge();
this.refreshBadge();
}
return this.handler;
}
/**
* Triggers an update for the badge number and loading status. Mandatory if showBadge is enabled.
* Refreshes badge number.
*
* @param {string} [siteId] Site ID or current Site if undefined.
* @param {number} [contactRequestsCount] Number of contact requests, if known.
* @param {boolean} [unreadOnly] If true only the unread conversations count is refreshed.
* @return {Promise<any>} Resolve when done.
*/
updateBadge(siteId?: string, contactRequestsCount?: number): void {
refreshBadge(siteId?: string, unreadOnly?: boolean): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (!siteId) {
return;
}
if (this.updating) {
// An update is already in prgoress.
return;
}
this.updating = true;
const promises = [];
let unreadCount = 0;
let unreadPlus = false;
promises.push(this.messagesProvider.getUnreadConversationsCount(undefined, siteId).then((unread) => {
unreadCount = parseInt(unread, 10);
unreadPlus = (typeof unread === 'string' && unread.slice(-1) === '+');
}).catch(() => {
// Ignore error.
promises.push(this.messagesProvider.refreshUnreadConversationCounts(siteId).catch(() => {
this.unreadCount = 0;
this.orMore = false;
}));
// Get the number of contact requests in 3.6+ sites if needed.
if (contactRequestsCount == null && this.messagesProvider.isGroupMessagingEnabled()) {
promises.push(this.messagesProvider.getContactRequestsCount(siteId).then((count) => {
contactRequestsCount = count;
}).catch(() => {
// Ignore errors
// Refresh the number of contact requests in 3.6+ sites.
if (!unreadOnly && this.messagesProvider.isGroupMessagingEnabled()) {
promises.push(this.messagesProvider.refreshContactRequestsCount(siteId).catch(() => {
this.contactRequestsCount = 0;
}));
}
Promise.all(promises).then(() => {
const totalCount = unreadCount + (contactRequestsCount || 0);
return Promise.all(promises).finally(() => {
this.updateBadge(siteId);
this.handler.loading = false;
});
}
/**
* Update badge number and push notifications counter from loaded data.
*
* @param {string} siteId Site ID.
*/
updateBadge(siteId: string): void {
const totalCount = this.unreadCount + (this.contactRequestsCount || 0);
if (totalCount > 0) {
this.handler.badge = totalCount + (unreadPlus ? '+' : '');
this.handler.badge = totalCount + (this.orMore ? '+' : '');
} else {
this.handler.badge = '';
}
// Update badge.
// Update push notifications badge.
this.pushNotificationsProvider.updateAddonCounter('AddonMessages', totalCount, siteId);
}).finally(() => {
this.handler.loading = false;
this.updating = false;
});
}
/**
@ -171,7 +169,7 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr
*/
execute(siteId?: string): Promise<any> {
if (this.sitesProvider.isCurrentSite(siteId)) {
this.eventsProvider.trigger(AddonMessagesProvider.READ_CRON_EVENT, {}, siteId);
this.refreshBadge();
}
if (this.appProvider.isDesktop() && this.localNotificationsProvider.isAvailable()) {
@ -199,8 +197,13 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr
*/
isSync(): boolean {
// This is done to use only wifi if using the fallback function.
if (this.appProvider.isDesktop()) {
// In desktop it is always sync, since it fetches messages to see if there's a new one.
return !this.messagesProvider.isMessageCountEnabled() || this.appProvider.isDesktop();
return true;
}
return !this.messagesProvider.isMessageCountEnabled() && !this.messagesProvider.isGroupMessagingEnabled();
}
/**

View File

@ -33,11 +33,11 @@ export class AddonMessagesProvider {
protected LIMIT_MESSAGES = AddonMessagesProvider.LIMIT_MESSAGES;
static NEW_MESSAGE_EVENT = 'addon_messages_new_message_event';
static READ_CHANGED_EVENT = 'addon_messages_read_changed_event';
static READ_CRON_EVENT = 'addon_messages_read_cron_event';
static OPEN_CONVERSATION_EVENT = 'addon_messages_open_conversation_event'; // Notify that a conversation should be opened.
static SPLIT_VIEW_LOAD_EVENT = 'addon_messages_split_view_load_event';
static UPDATE_CONVERSATION_LIST_EVENT = 'addon_messages_update_conversation_list_event';
static MEMBER_INFO_CHANGED_EVENT = 'addon_messages_member_changed_event';
static UNREAD_CONVERSATION_COUNTS_EVENT = 'addon_messages_unread_conversation_counts_event';
static CONTACT_REQUESTS_COUNT_EVENT = 'addon_messages_contact_requests_count_event';
static POLL_INTERVAL = 10000;
static PUSH_SIMULATION_COMPONENT = 'AddonMessagesPushSimulation';
@ -384,6 +384,15 @@ export class AddonMessagesProvider {
return this.ROOT_CACHE_KEY + 'count:' + userId;
}
/**
* Get the cache key for unread conversation counts.
*
* @return {string} Cache key.
*/
protected getCacheKeyForUnreadConversationCounts(): string {
return this.ROOT_CACHE_KEY + 'unreadConversationCounts';
}
/**
* Get the cache key for the list of discussions.
*
@ -449,6 +458,15 @@ export class AddonMessagesProvider {
return this.getCommonCacheKeyForUserConversations(userId) + ':' + type + ':' + favourites;
}
/**
* Get cache key for conversation counts.
*
* @return {string} Cache key.
*/
protected getCacheKeyForConversationCounts(): string {
return this.ROOT_CACHE_KEY + 'conversationCounts';
}
/**
* Get cache key for member info.
*
@ -943,6 +961,31 @@ export class AddonMessagesProvider {
});
}
/**
* Get conversation counts by type.
*
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved with favourite, individual and group conversation counts.
* @since 3.6
*/
getConversationCounts(siteId?: string): Promise<{favourites: number, individual: number, group: number}> {
return this.sitesProvider.getSite(siteId).then((site) => {
const preSets = {
cacheKey: this.getCacheKeyForConversationCounts(),
};
return site.read('core_message_get_conversation_counts', {}, preSets).then((result) => {
const counts = {
favourites: result.favourites,
individual: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
group: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP]
};
return counts;
});
});
}
/**
* Return the current user's discussion with another user.
*
@ -1292,58 +1335,77 @@ export class AddonMessagesProvider {
}
/**
* Get unread conversations count. Do not cache calls.
* Get unread conversation counts by type.
*
* @param {number} [userId] The user id who received the message. If not defined, use current user.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved with the message unread count.
* @return {Promise<any>} Resolved with the unread favourite, individual and group conversation counts.
*/
getUnreadConversationsCount(userId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
userId = userId || site.getUserId();
getUnreadConversationCounts(siteId?: string):
Promise<{favourites: number, individual: number, group: number, orMore?: boolean}> {
return this.sitesProvider.getSite(siteId).then((site) => {
let promise: Promise<{favourites: number, individual: number, group: number, orMore?: boolean}>;
if (this.isGroupMessagingEnabled()) {
// @since 3.6
const preSets = {
cacheKey: this.getCacheKeyForUnreadConversationCounts(),
};
promise = site.read('core_message_get_unread_conversation_counts', {}, preSets).then((result) => {
return {
favourites: result.favourites,
individual: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
group: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP]
};
});
} else if (this.isMessageCountEnabled()) {
// @since 3.2
if (site.wsAvailable('core_message_get_unread_conversations_count')) {
const params = {
useridto: userId
useridto: site.getUserId(),
},
preSets = {
cacheKey: this.getCacheKeyForMessageCount(userId),
getFromCache: false,
emergencyCache: true,
saveToCache: true,
cacheKey: this.getCacheKeyForMessageCount(site.getUserId()),
typeExpected: 'number'
};
return site.read('core_message_get_unread_conversations_count', params, preSets).catch(() => {
// Return no messages if the call fails.
return 0;
promise = site.read('core_message_get_unread_conversations_count', params, preSets).then((count) => {
return { favourites: 0, individual: count, group: 0 };
});
}
} else {
// Fallback call.
const params = {
read: 0,
limitfrom: 0,
limitnum: this.LIMIT_MESSAGES + 1,
useridto: userId,
useridto: site.getUserId(),
useridfrom: 0,
};
return this.getMessages(params, undefined, false, siteId).then((response) => {
promise = this.getMessages(params, undefined, false, siteId).then((response) => {
// Count the discussions by filtering same senders.
const discussions = {};
response.messages.forEach((message) => {
discussions[message.useridto] = 1;
});
const count = Object.keys(discussions).length;
// Add + sign if there are more than the limit reachable.
return (count > this.LIMIT_MESSAGES) ? count + '+' : count;
}).catch(() => {
// Return no messages if the call fails.
return 0;
return {
favourites: 0,
individual: count,
group: 0,
orMore: count > this.LIMIT_MESSAGES
};
});
}
return promise.then((counts) => {
// Notify the new counts so all views are updated.
this.eventsProvider.trigger(AddonMessagesProvider.UNREAD_CONVERSATION_COUNTS_EVENT, counts, site.id);
return counts;
});
});
}
@ -1535,6 +1597,18 @@ export class AddonMessagesProvider {
});
}
/**
* Invalidate conversation counts cache.
*
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Resolved when done.
*/
invalidateConversationCounts(siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.invalidateWsCacheForKey(this.getCacheKeyForConversationCounts());
});
}
/**
* Invalidate discussion cache.
*
@ -1619,6 +1693,25 @@ export class AddonMessagesProvider {
]);
}
/**
* Invalidate unread conversation counts cache.
*
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Resolved when done.
*/
invalidateUnreadConversationCounts(siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
if (this.isGroupMessagingEnabled()) {
// @since 3.6
return site.invalidateWsCacheForKey(this.getCacheKeyForUnreadConversationCounts());
} else if (this.isMessageCountEnabled()) {
// @since 3.2
return site.invalidateWsCacheForKey(this.getCacheKeyForMessageCount(site.getUserId()));
}
});
}
/**
* Checks if the a user is blocked by the current user.
*
@ -1816,6 +1909,23 @@ export class AddonMessagesProvider {
});
}
/**
* Refresh unread conversation counts and trigger event.
*
* @param {string} [siteId] Site ID. If not defined, use current site.
* @param {number} [conversationId] ID of the conversation that was read.
* @param {number} [userId] ID of ther other user of the conversation that was read.
* @return {Promise<any>} Resolved with the unread favourite, individual and group conversation counts.
*/
refreshUnreadConversationCounts(siteId?: string, conversationId?: number, userId?: number):
Promise<{favourites: number, individual: number, group: number, orMore?: boolean}> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.invalidateUnreadConversationCounts(siteId).then(() => {
return this.getUnreadConversationCounts(siteId);
});
}
/**
* Remove a contact.
*