MOBILE-2630 messages: Fetch conversations when option is expanded

main
Dani Palou 2019-01-02 14:34:54 +01:00
parent 15731c47c3
commit 0a59a42006
4 changed files with 204 additions and 106 deletions

View File

@ -630,7 +630,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
conversationId: this.conversationId, conversationId: this.conversationId,
userId: this.userId, userId: this.userId,
message: this.lastMessage.text, message: this.lastMessage.text,
timecreated: this.lastMessage.timecreated timecreated: this.lastMessage.timecreated,
isfavourite: this.conversation && this.conversation.isfavourite,
type: this.conversation && this.conversation.type
}, this.siteId); }, this.siteId);
// Update navBar links and buttons. // Update navBar links and buttons.

View File

@ -27,13 +27,13 @@
<ion-badge *ngIf="contactRequestsCount > 0" item-end>{{contactRequestsCount}}</ion-badge> <ion-badge *ngIf="contactRequestsCount > 0" item-end>{{contactRequestsCount}}</ion-badge>
</a> </a>
<!-- Favourite conversations. --> <!-- Favourite conversations. -->
<ion-item-divider text-wrap *ngIf="favourites.conversations" (click)="toggle(favourites)" class="core-expandable"> <ion-item-divider text-wrap (click)="toggle(favourites)" class="core-expandable">
<core-icon *ngIf="!favourites.expanded" name="fa-caret-right" item-start></core-icon> <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-icon *ngIf="favourites.expanded" name="fa-caret-down" item-start></core-icon>
{{ 'core.favourites' | translate }} ({{ favourites.count }}) {{ 'core.favourites' | translate }} ({{ favourites.count }})
<ion-badge item-end *ngIf="favourites.unread">{{ favourites.unread }}</ion-badge> <ion-badge item-end *ngIf="favourites.unread">{{ favourites.unread }}</ion-badge>
</ion-item-divider> </ion-item-divider>
<div *ngIf="favourites.conversations && favourites.expanded"> <div *ngIf="favourites.conversations && favourites.expanded && !favourites.loading">
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}"></ng-container> <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}"></ng-container>
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
<core-infinite-loading [enabled]="favourites.canLoadMore" (action)="loadMoreConversations(favourites, $event)" [error]="favourites.loadMoreError"></core-infinite-loading> <core-infinite-loading [enabled]="favourites.canLoadMore" (action)="loadMoreConversations(favourites, $event)" [error]="favourites.loadMoreError"></core-infinite-loading>
@ -41,15 +41,18 @@
<p>{{ 'addon.messages.nofavourites' | translate }}</p> <p>{{ 'addon.messages.nofavourites' | translate }}</p>
</ion-item> </ion-item>
</div> </div>
<ion-item text-center *ngIf="favourites.loading">
<ion-spinner></ion-spinner>
</ion-item>
<!-- Group conversations. --> <!-- Group conversations. -->
<ion-item-divider text-wrap *ngIf="group.conversations" (click)="toggle(group)" class="core-expandable"> <ion-item-divider text-wrap (click)="toggle(group)" class="core-expandable">
<core-icon *ngIf="!group.expanded" name="fa-caret-right" item-start></core-icon> <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> <core-icon *ngIf="group.expanded" name="fa-caret-down" item-start></core-icon>
{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }}) {{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})
<ion-badge item-end *ngIf="group.unread">{{ group.unread }}</ion-badge> <ion-badge item-end *ngIf="group.unread">{{ group.unread }}</ion-badge>
</ion-item-divider> </ion-item-divider>
<div *ngIf="group.conversations && group.expanded"> <div *ngIf="group.conversations && group.expanded && !group.loading">
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}"></ng-container> <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}"></ng-container>
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
<core-infinite-loading [enabled]="group.canLoadMore" (action)="loadMoreConversations(group, $event)" [error]="group.loadMoreError"></core-infinite-loading> <core-infinite-loading [enabled]="group.canLoadMore" (action)="loadMoreConversations(group, $event)" [error]="group.loadMoreError"></core-infinite-loading>
@ -57,14 +60,17 @@
<p>{{ 'addon.messages.nogroupconversations' | translate }}</p> <p>{{ 'addon.messages.nogroupconversations' | translate }}</p>
</ion-item> </ion-item>
</div> </div>
<ion-item text-center *ngIf="group.loading">
<ion-spinner></ion-spinner>
</ion-item>
<ion-item-divider text-wrap *ngIf="individual.conversations" (click)="toggle(individual)" class="core-expandable"> <ion-item-divider text-wrap (click)="toggle(individual)" class="core-expandable">
<core-icon *ngIf="!individual.expanded" name="fa-caret-right" item-start></core-icon> <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> <core-icon *ngIf="individual.expanded" name="fa-caret-down" item-start></core-icon>
{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }}) {{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})
<ion-badge item-end *ngIf="individual.unread">{{ individual.unread }}</ion-badge> <ion-badge item-end *ngIf="individual.unread">{{ individual.unread }}</ion-badge>
</ion-item-divider> </ion-item-divider>
<div *ngIf="individual.conversations && individual.expanded"> <div *ngIf="individual.conversations && individual.expanded && !individual.loading">
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}"></ng-container> <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}"></ng-container>
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
<core-infinite-loading [enabled]="individual.canLoadMore" (action)="loadMoreConversations(individual, $event)" [error]="individual.loadMoreError"></core-infinite-loading> <core-infinite-loading [enabled]="individual.canLoadMore" (action)="loadMoreConversations(individual, $event)" [error]="individual.loadMoreError"></core-infinite-loading>
@ -72,6 +78,10 @@
<p>{{ 'addon.messages.noindividualconversations' | translate }}</p> <p>{{ 'addon.messages.noindividualconversations' | translate }}</p>
</ion-item> </ion-item>
</div> </div>
<ion-item text-center *ngIf="individual.loading">
<ion-spinner></ion-spinner>
</ion-item>
</ion-list> </ion-list>
</core-loading> </core-loading>
</ion-content> </ion-content>

View File

@ -89,8 +89,16 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
// Update conversations when new message is received. // Update conversations when new message is received.
this.newMessagesObserver = eventsProvider.on(AddonMessagesProvider.NEW_MESSAGE_EVENT, (data) => { this.newMessagesObserver = eventsProvider.on(AddonMessagesProvider.NEW_MESSAGE_EVENT, (data) => {
// Check if the new message belongs to the option that is currently expanded.
const expandedOption = this.getExpandedOption(),
messageOption = this.getConversationOption(data);
if (expandedOption != messageOption) {
return; // Message doesn't belong to current list, stop.
}
// Search the conversation to update. // Search the conversation to update.
const conversation = this.findConversation(data.conversationId, data.userId); const conversation = this.findConversation(data.conversationId, data.userId, expandedOption);
if (typeof conversation == 'undefined') { if (typeof conversation == 'undefined') {
// Probably a new conversation, refresh the list. // Probably a new conversation, refresh the list.
@ -135,7 +143,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
// Load a discussion if we receive an event to do so. // Load a discussion if we receive an event to do so.
this.openConversationObserver = eventsProvider.on(AddonMessagesProvider.OPEN_CONVERSATION_EVENT, (data) => { this.openConversationObserver = eventsProvider.on(AddonMessagesProvider.OPEN_CONVERSATION_EVENT, (data) => {
if (data.conversationId || data.userId) { if (data.conversationId || data.userId) {
this.gotoConversation(data.conversationId, data.userId, undefined, true); this.gotoConversation(data.conversationId, data.userId);
} }
}, this.siteId); }, this.siteId);
@ -183,18 +191,17 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
return; return;
} }
const updateConversations = (conversations: any[]): void => { const expandedOption = this.getExpandedOption();
if (!conversations || conversations.length <= 0) { if (expandedOption == this.individual || expandedOption == this.favourites) {
if (!expandedOption.conversations || expandedOption.conversations.length <= 0) {
return; return;
} }
const conversation = conversations.find((conv) => conv.userid == data.userId);
const conversation = this.findConversation(undefined, data.userId, expandedOption);
if (conversation) { if (conversation) {
conversation.isblocked = data.userBlocked; conversation.isblocked = data.userBlocked;
} }
}; }
updateConversations(this.individual.conversations);
updateConversations(this.favourites.conversations);
}, this.siteId); }, this.siteId);
} }
@ -211,13 +218,10 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
if (!this.conversationId && this.splitviewCtrl.isOn()) { if (!this.conversationId && this.splitviewCtrl.isOn()) {
// Load the first conversation. // Load the first conversation.
let conversation; let conversation;
const expandedOption = this.getExpandedOption();
if (this.favourites.expanded) { if (expandedOption) {
conversation = this.favourites.conversations[0]; conversation = expandedOption.conversations[0];
} else if (this.group.expanded) {
conversation = this.group.conversations[0];
} else if (this.individual.expanded) {
conversation = this.individual.conversations[0];
} }
if (conversation) { if (conversation) {
@ -230,53 +234,53 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
/** /**
* Fetch conversations. * Fetch conversations.
* *
* @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts.
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected fetchData(): Promise<any> { protected fetchData(refreshUnreadCounts: boolean = true): Promise<any> {
this.loadingMessage = this.loadingString; this.loadingMessage = this.loadingString;
// Load the first conversations of each type. // Load the amount of conversations and contact requests.
const promises = []; const promises = [];
let offlineMessages;
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.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.messagesProvider.getContactRequestsCount()); // View updated by the event observer.
promises.push(this.messagesOffline.getAllMessages().then((messages) => {
offlineMessages = messages;
}));
return Promise.all(promises).then(() => { return Promise.all(promises).then(() => {
return this.loadOfflineMessages(offlineMessages);
}).then(() => {
if (offlineMessages && offlineMessages.length) {
// Sort the conversations, the offline messages could affect the order.
this.favourites.conversations = this.messagesProvider.sortConversations(this.favourites.conversations);
this.group.conversations = this.messagesProvider.sortConversations(this.group.conversations);
this.individual.conversations = this.messagesProvider.sortConversations(this.individual.conversations);
}
if (typeof this.favourites.expanded == 'undefined') { if (typeof this.favourites.expanded == 'undefined') {
// The expanded status hasn't been initialized. Do it now. // The expanded status hasn't been initialized. Do it now.
if (this.conversationId) { if (this.conversationId) {
// A certain conversation should be opened, expand its option. // A certain conversation should be opened.
// We don't know which option it belongs to, so we need to fetch the data for all of them.
const promises = [];
promises.push(this.fetchDataForOption(this.favourites, false, refreshUnreadCounts));
promises.push(this.fetchDataForOption(this.group, false, refreshUnreadCounts));
promises.push(this.fetchDataForOption(this.individual, false, refreshUnreadCounts));
return Promise.all(promises).then(() => {
// All conversations have been loaded, find the one we need to load and expand its option.
const conversation = this.findConversation(this.conversationId); const conversation = this.findConversation(this.conversationId);
if (conversation) { if (conversation) {
const option = this.getConversationOption(conversation); const option = this.getConversationOption(conversation);
this.expandOption(option);
return; return this.expandOption(option, refreshUnreadCounts);
} else {
// Conversation not found, just open the default option.
this.calculateExpandedStatus();
// Now load the data for the expanded option.
return this.fetchDataForExpandedOption(refreshUnreadCounts);
} }
});
} }
// No conversation specified or not found, determine which one should be expanded. // No conversation specified or not found, determine which one should be expanded.
this.favourites.expanded = this.favourites.count != 0; this.calculateExpandedStatus();
this.group.expanded = this.favourites.count == 0 && this.group.count != 0;
this.individual.expanded = this.favourites.count == 0 && this.group.count == 0;
} }
// Now load the data for the expanded option.
return this.fetchDataForExpandedOption(refreshUnreadCounts);
}).catch((error) => { }).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true); this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true);
}).finally(() => { }).finally(() => {
@ -284,27 +288,91 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
}); });
} }
/**
* Calculate which option should be expanded initially.
*/
protected calculateExpandedStatus(): void {
this.favourites.expanded = this.favourites.count != 0;
this.group.expanded = this.favourites.count == 0 && this.group.count != 0;
this.individual.expanded = this.favourites.count == 0 && this.group.count == 0;
}
/**
* Fetch data for the expanded option.
*
* @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts.
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchDataForExpandedOption(refreshUnreadCounts: boolean = true): Promise<any> {
const expandedOption = this.getExpandedOption();
if (expandedOption) {
return this.fetchDataForOption(expandedOption, false, refreshUnreadCounts);
} else {
// All options are collapsed, update the counts.
const promises = [];
promises.push(this.fetchConversationCounts());
if (refreshUnreadCounts) {
promises.push(this.messagesProvider.refreshUnreadConversationCounts()); // View updated by the event observer.
}
return Promise.all(promises);
}
}
/** /**
* Fetch data for a certain option. * Fetch data for a certain option.
* *
* @param {any} option The option to fetch data for. * @param {any} option The option to fetch data for.
* @param {boolean} [loadingMore} Whether we are loading more data or just the first ones. * @param {boolean} [loadingMore} Whether we are loading more data or just the first ones.
* @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts.
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
fetchDataForOption(option: any, loadingMore?: boolean): Promise<void> { fetchDataForOption(option: any, loadingMore?: boolean, refreshUnreadCounts: boolean = true): Promise<void> {
option.loadMoreError = false; option.loadMoreError = false;
const limitFrom = loadingMore ? option.conversations.length : 0; const limitFrom = loadingMore ? option.conversations.length : 0,
promises = [];
let data,
offlineMessages;
return this.messagesProvider.getConversations(option.type, option.favourites, limitFrom).then((data) => { // Get the conversations and, if needed, the offline messages. Always try to get the latest data.
if (loadingMore) { promises.push(this.messagesProvider.invalidateConversations().catch(() => {
option.conversations = option.conversations.concat(data.conversations); // Shouldn't happen.
} else { }).then(() => {
option.conversations = data.conversations; return this.messagesProvider.getConversations(option.type, option.favourites, limitFrom);
}).then((result) => {
data = result;
}));
if (!loadingMore) {
promises.push(this.messagesOffline.getAllMessages().then((data) => {
offlineMessages = data;
}));
promises.push(this.fetchConversationCounts());
if (refreshUnreadCounts) {
promises.push(this.messagesProvider.refreshUnreadConversationCounts()); // View updated by the event observer.
}
} }
option.unread = 0; // @todo. return Promise.all(promises).then(() => {
if (loadingMore) {
option.conversations = option.conversations.concat(data.conversations);
option.canLoadMore = data.canLoadMore; option.canLoadMore = data.canLoadMore;
} else {
option.conversations = data.conversations;
option.canLoadMore = data.canLoadMore;
if (offlineMessages && offlineMessages.length) {
return this.loadOfflineMessages(option, offlineMessages).then(() => {
// Sort the conversations, the offline messages could affect the order.
option.conversations = this.messagesProvider.sortConversations(option.conversations);
});
}
}
}); });
} }
@ -314,7 +382,12 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected fetchConversationCounts(): Promise<void> { protected fetchConversationCounts(): Promise<void> {
return this.messagesProvider.getConversationCounts().then((counts) => { // Always try to get the latest data.
return this.messagesProvider.invalidateConversationCounts().catch(() => {
// Shouldn't happen.
}).then(() => {
return this.messagesProvider.getConversationCounts();
}).then((counts) => {
this.favourites.count = counts.favourites; this.favourites.count = counts.favourites;
this.individual.count = counts.individual; this.individual.count = counts.individual;
this.group.count = counts.group; this.group.count = counts.group;
@ -326,25 +399,42 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
* *
* @param {number} conversationId The conversation ID to search. * @param {number} conversationId The conversation ID to search.
* @param {number} userId User ID to search (if no conversationId). * @param {number} userId User ID to search (if no conversationId).
* @param {any} [option] The option to search in. If not defined, search in all options.
* @return {any} Conversation. * @return {any} Conversation.
*/ */
protected findConversation(conversationId: number, userId?: number): any { protected findConversation(conversationId: number, userId?: number, option?: any): any {
if (conversationId) { if (conversationId) {
const conversations = (this.favourites.conversations || []).concat(this.group.conversations || []) const conversations = option ? (option.conversations || []) : ((this.favourites.conversations || [])
.concat(this.individual.conversations || []); .concat(this.group.conversations || []).concat(this.individual.conversations || []));
return conversations.find((conv) => { return conversations.find((conv) => {
return conv.id == conversationId; return conv.id == conversationId;
}); });
} }
const conversations = (this.favourites.conversations || []).concat(this.individual.conversations || []); const conversations = option ? (option.conversations || []) :
((this.favourites.conversations || []).concat(this.individual.conversations || []));
return conversations.find((conv) => { return conversations.find((conv) => {
return conv.userid == userId; return conv.userid == userId;
}); });
} }
/**
* Get the option that is currently expanded, undefined if they are all collapsed.
*
* @return {any} Option currently expanded.
*/
protected getExpandedOption(): any {
if (this.favourites.expanded) {
return this.favourites;
} else if (this.group.expanded) {
return this.group;
} else if (this.individual.expanded) {
return this.individual;
}
}
/** /**
* Navigate to contacts view. * Navigate to contacts view.
*/ */
@ -358,9 +448,8 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
* @param {number} conversationId Conversation Id to load. * @param {number} conversationId Conversation Id to load.
* @param {number} userId User of the conversation. Only if there is no conversationId. * @param {number} userId User of the conversation. Only if there is no conversationId.
* @param {number} [messageId] Message to scroll after loading the discussion. Used when searching. * @param {number} [messageId] Message to scroll after loading the discussion. Used when searching.
* @param {boolean} [scrollToConversation] Whether to scroll to the conversation.
*/ */
gotoConversation(conversationId: number, userId?: number, messageId?: number, scrollToConversation?: boolean): void { gotoConversation(conversationId: number, userId?: number, messageId?: number): void {
this.selectedConversationId = conversationId; this.selectedConversationId = conversationId;
this.selectedUserId = userId; this.selectedUserId = userId;
@ -372,23 +461,6 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
params['message'] = messageId; params['message'] = messageId;
} }
this.splitviewCtrl.push('AddonMessagesDiscussionPage', params); this.splitviewCtrl.push('AddonMessagesDiscussionPage', params);
if (scrollToConversation) {
// Search the conversation.
const conversation = this.findConversation(conversationId, userId);
if (conversation) {
// First expand the option if it isn't expanded.
const option = this.getConversationOption(conversation);
this.expandOption(option);
// Wait for the view to expand the option.
setTimeout(() => {
// Now scroll to the conversation.
this.domUtils.scrollToElementBySelector(this.content, '#addon-message-conversation-' +
(conversation.id ? conversation.id : 'user-' + conversation.userid));
});
}
}
} }
/** /**
@ -417,16 +489,17 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
/** /**
* Load offline messages into the conversations. * Load offline messages into the conversations.
* *
* @param {any} option The option where the messages should be loaded.
* @param {any[]} messages Offline messages. * @param {any[]} messages Offline messages.
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected loadOfflineMessages(messages: any[]): Promise<any> { protected loadOfflineMessages(option: any, messages: any[]): Promise<any> {
const promises = []; const promises = [];
messages.forEach((message) => { messages.forEach((message) => {
if (message.conversationid) { if (message.conversationid) {
// It's an existing conversation. Search it. // It's an existing conversation. Search it in the current option.
let conversation = this.findConversation(message.conversationid); let conversation = this.findConversation(message.conversationid, undefined, option);
if (conversation) { if (conversation) {
// Check if it's the last message. Offline messages are considered more recent than sent messages. // Check if it's the last message. Offline messages are considered more recent than sent messages.
@ -436,16 +509,19 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
this.addLastOfflineMessage(conversation, message); this.addLastOfflineMessage(conversation, message);
} }
} else { } else {
// Conversation not found, it's probably an old one. Add it. // Conversation not found, it could be an old one or the message could belong to another option.
conversation = message.conversation || {}; conversation = message.conversation || {};
conversation.id = message.conversationid; conversation.id = message.conversationid;
if (this.getConversationOption(conversation) == option) {
// Message belongs to current option, add the conversation.
this.addLastOfflineMessage(conversation, message); this.addLastOfflineMessage(conversation, message);
this.addOfflineConversation(conversation); this.addOfflineConversation(conversation);
} }
} else { }
// Its a new conversation. Check if we already created it (there is more than one message for the same user). } else if (option == this.individual) {
const conversation = this.findConversation(undefined, message.touserid); // It's a new conversation. Check if we already created it (there is more than one message for the same user).
const conversation = this.findConversation(undefined, message.touserid, option);
message.text = message.smallmessage; message.text = message.smallmessage;
@ -455,7 +531,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
this.addLastOfflineMessage(conversation, message); this.addLastOfflineMessage(conversation, message);
} }
} else { } else {
// Get the user data and create a new conversation. // Get the user data and create a new conversation if it belongs to the current option.
promises.push(this.userProvider.getProfile(message.touserid, undefined, true).catch(() => { promises.push(this.userProvider.getProfile(message.touserid, undefined, true).catch(() => {
// User not found. // User not found.
}).then((user) => { }).then((user) => {
@ -523,18 +599,13 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise<any> { refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise<any> {
// Don't invalidate conversations and so, they always try to get latest data.
const promises = [ const promises = [
this.messagesProvider.invalidateConversations(),
this.messagesProvider.invalidateConversationCounts(),
this.messagesProvider.invalidateContactRequestsCountCache() this.messagesProvider.invalidateContactRequestsCountCache()
]; ];
if (refreshUnreadCounts) {
promises.push(this.messagesProvider.invalidateUnreadConversationCounts());
}
return this.utils.allPromises(promises).finally(() => { return this.utils.allPromises(promises).finally(() => {
return this.fetchData().finally(() => { return this.fetchData(refreshUnreadCounts).finally(() => {
if (refresher) { if (refresher) {
refresher.complete(); refresher.complete();
} }
@ -552,7 +623,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
// Already expanded, close it. // Already expanded, close it.
option.expanded = false; option.expanded = false;
} else { } else {
this.expandOption(option); this.expandOption(option).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true);
});
} }
} }
@ -560,13 +633,25 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
* Expand a certain option. * Expand a certain option.
* *
* @param {any} option The option to expand. * @param {any} option The option to expand.
* @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts.
* @return {Promise<any>} Promise resolved when done.
*/ */
protected expandOption(option: any): void { protected expandOption(option: any, refreshUnreadCounts: boolean = true): Promise<any> {
// Collapse all and expand the right one. // Collapse all and expand the right one.
this.favourites.expanded = false; this.favourites.expanded = false;
this.group.expanded = false; this.group.expanded = false;
this.individual.expanded = false; this.individual.expanded = false;
option.expanded = true; option.expanded = true;
option.loading = true;
return this.fetchDataForOption(option, false, refreshUnreadCounts).catch((error) => {
option.expanded = false;
return Promise.reject(error);
}).finally(() => {
option.loading = false;
});
} }
/** /**

View File

@ -917,10 +917,10 @@ export class AddonMessagesProvider {
* Get the discussions of a certain user. This function is used in Moodle sites higher than 3.6. * Get the discussions of a certain user. This function is used in Moodle sites higher than 3.6.
* If the site is older than 3.6, please use getDiscussions. * If the site is older than 3.6, please use getDiscussions.
* *
* @param {number} [limitFrom=0] The offset to start at.
* @param {number} [type] Filter by type. * @param {number} [type] Filter by type.
* @param {boolean} [favourites] Whether to restrict the results to contain NO favourite conversations (false), ONLY favourite * @param {boolean} [favourites] Whether to restrict the results to contain NO favourite conversations (false), ONLY favourite
* conversation (true), or ignore any restriction altogether (undefined or null). * conversation (true), or ignore any restriction altogether (undefined or null).
* @param {number} [limitFrom=0] The offset to start at.
* @param {string} [siteId] Site ID. If not defined, use current site. * @param {string} [siteId] Site ID. If not defined, use current site.
* @param {number} [userId] User ID. If not defined, current user in the site. * @param {number} [userId] User ID. If not defined, current user in the site.
* @return {Promise<any>} Promise resolved with the conversations. * @return {Promise<any>} Promise resolved with the conversations.
@ -966,13 +966,15 @@ export class AddonMessagesProvider {
* Get conversation counts by type. * Get conversation counts by type.
* *
* @param {string} [siteId] Site ID. If not defined, use current site. * @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise<any>} Promise resolved with favourite, individual and group conversation counts. * @return {Promise<favourites: number, individual: number, group: number>} Promise resolved with favourite, individual and
* group conversation counts.
* @since 3.6 * @since 3.6
*/ */
getConversationCounts(siteId?: string): Promise<{favourites: number, individual: number, group: number}> { getConversationCounts(siteId?: string): Promise<{favourites: number, individual: number, group: number}> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const preSets = { const preSets = {
cacheKey: this.getCacheKeyForConversationCounts(), cacheKey: this.getCacheKeyForConversationCounts()
}; };
return site.read('core_message_get_conversation_counts', {}, preSets).then((result) => { return site.read('core_message_get_conversation_counts', {}, preSets).then((result) => {
@ -1350,7 +1352,7 @@ export class AddonMessagesProvider {
if (this.isGroupMessagingEnabled()) { if (this.isGroupMessagingEnabled()) {
// @since 3.6 // @since 3.6
const preSets = { const preSets = {
cacheKey: this.getCacheKeyForUnreadConversationCounts(), cacheKey: this.getCacheKeyForUnreadConversationCounts()
}; };
promise = site.read('core_message_get_unread_conversation_counts', {}, preSets).then((result) => { promise = site.read('core_message_get_unread_conversation_counts', {}, preSets).then((result) => {
@ -1914,12 +1916,11 @@ export class AddonMessagesProvider {
* Refresh unread conversation counts and trigger event. * Refresh unread conversation counts and trigger event.
* *
* @param {string} [siteId] Site ID. If not defined, use current site. * @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. * @return {Promise<any>} Resolved with the unread favourite, individual and group conversation counts.
*/ */
refreshUnreadConversationCounts(siteId?: string, conversationId?: number, userId?: number): refreshUnreadConversationCounts(siteId?: string):
Promise<{favourites: number, individual: number, group: number, orMore?: boolean}> { Promise<{favourites: number, individual: number, group: number, orMore?: boolean}> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.invalidateUnreadConversationCounts(siteId).then(() => { return this.invalidateUnreadConversationCounts(siteId).then(() => {