From 15731c47c3c321a0e23dfd80aaf1889e9323ba33 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 2 Jan 2019 10:35:35 +0100 Subject: [PATCH 1/5] MOBILE-2630 message: Decrease time to check unread messages --- src/addon/messages/providers/mainmenu-handler.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/addon/messages/providers/mainmenu-handler.ts b/src/addon/messages/providers/mainmenu-handler.ts index 36df9b041..170d86082 100644 --- a/src/addon/messages/providers/mainmenu-handler.ts +++ b/src/addon/messages/providers/mainmenu-handler.ts @@ -187,7 +187,13 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr * @return {number} Time between consecutive executions (in ms). */ getInterval(): number { - return this.appProvider.isDesktop() ? 60000 : 600000; // 1 or 10 minutes. + if (this.appProvider.isDesktop()) { + return 60000; // Desktop usually has a WiFi connection, check it every minute. + } else if (this.messagesProvider.isGroupMessagingEnabled() || this.messagesProvider.isMessageCountEnabled()) { + return 300000; // We have a WS to check the number, check it every 5 minutes. + } else { + return 600000; // Check it every 10 minutes. + } } /** From 0a59a420062416b8c4474bf75e2516eb04a552e1 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 2 Jan 2019 14:34:54 +0100 Subject: [PATCH 2/5] MOBILE-2630 messages: Fetch conversations when option is expanded --- .../messages/pages/discussion/discussion.ts | 4 +- .../group-conversations.html | 22 +- .../group-conversations.ts | 269 ++++++++++++------ src/addon/messages/providers/messages.ts | 15 +- 4 files changed, 204 insertions(+), 106 deletions(-) diff --git a/src/addon/messages/pages/discussion/discussion.ts b/src/addon/messages/pages/discussion/discussion.ts index 8de0d7dd0..6b94fe915 100644 --- a/src/addon/messages/pages/discussion/discussion.ts +++ b/src/addon/messages/pages/discussion/discussion.ts @@ -630,7 +630,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy { conversationId: this.conversationId, userId: this.userId, 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); // Update navBar links and buttons. diff --git a/src/addon/messages/pages/group-conversations/group-conversations.html b/src/addon/messages/pages/group-conversations/group-conversations.html index ddf0ef5c4..f455f8428 100644 --- a/src/addon/messages/pages/group-conversations/group-conversations.html +++ b/src/addon/messages/pages/group-conversations/group-conversations.html @@ -27,13 +27,13 @@ {{contactRequestsCount}} - + {{ 'core.favourites' | translate }} ({{ favourites.count }}) {{ favourites.unread }} -
+
@@ -41,15 +41,18 @@

{{ 'addon.messages.nofavourites' | translate }}

+ + + - + {{ 'addon.messages.groupconversations' | translate }} ({{ group.count }}) {{ group.unread }} -
+
@@ -57,14 +60,17 @@

{{ 'addon.messages.nogroupconversations' | translate }}

+ + + - + {{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }}) {{ individual.unread }} -
+
@@ -72,6 +78,10 @@

{{ 'addon.messages.noindividualconversations' | translate }}

+ + + + diff --git a/src/addon/messages/pages/group-conversations/group-conversations.ts b/src/addon/messages/pages/group-conversations/group-conversations.ts index 86b78189a..acfa047f7 100644 --- a/src/addon/messages/pages/group-conversations/group-conversations.ts +++ b/src/addon/messages/pages/group-conversations/group-conversations.ts @@ -89,8 +89,16 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { // Update conversations when new message is received. 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. - const conversation = this.findConversation(data.conversationId, data.userId); + const conversation = this.findConversation(data.conversationId, data.userId, expandedOption); if (typeof conversation == 'undefined') { // 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. this.openConversationObserver = eventsProvider.on(AddonMessagesProvider.OPEN_CONVERSATION_EVENT, (data) => { if (data.conversationId || data.userId) { - this.gotoConversation(data.conversationId, data.userId, undefined, true); + this.gotoConversation(data.conversationId, data.userId); } }, this.siteId); @@ -183,18 +191,17 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { return; } - const updateConversations = (conversations: any[]): void => { - if (!conversations || conversations.length <= 0) { + const expandedOption = this.getExpandedOption(); + if (expandedOption == this.individual || expandedOption == this.favourites) { + if (!expandedOption.conversations || expandedOption.conversations.length <= 0) { return; } - const conversation = conversations.find((conv) => conv.userid == data.userId); + + const conversation = this.findConversation(undefined, data.userId, expandedOption); if (conversation) { conversation.isblocked = data.userBlocked; } - }; - - updateConversations(this.individual.conversations); - updateConversations(this.favourites.conversations); + } }, this.siteId); } @@ -211,13 +218,10 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { if (!this.conversationId && this.splitviewCtrl.isOn()) { // Load the first conversation. let conversation; + const expandedOption = this.getExpandedOption(); - if (this.favourites.expanded) { - conversation = this.favourites.conversations[0]; - } else if (this.group.expanded) { - conversation = this.group.conversations[0]; - } else if (this.individual.expanded) { - conversation = this.individual.conversations[0]; + if (expandedOption) { + conversation = expandedOption.conversations[0]; } if (conversation) { @@ -230,53 +234,53 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { /** * Fetch conversations. * + * @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts. * @return {Promise} Promise resolved when done. */ - protected fetchData(): Promise { + protected fetchData(refreshUnreadCounts: boolean = true): Promise { this.loadingMessage = this.loadingString; - // Load the first conversations of each type. + // Load the amount of conversations and contact requests. 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.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; - })); 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') { // The expanded status hasn't been initialized. Do it now. if (this.conversationId) { - // A certain conversation should be opened, expand its option. - const conversation = this.findConversation(this.conversationId); - if (conversation) { - const option = this.getConversationOption(conversation); - this.expandOption(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 = []; - return; - } + 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); + if (conversation) { + const option = this.getConversationOption(conversation); + + 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. - 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; + this.calculateExpandedStatus(); } + + // Now load the data for the expanded option. + return this.fetchDataForExpandedOption(refreshUnreadCounts); }).catch((error) => { this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true); }).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} Promise resolved when done. + */ + protected fetchDataForExpandedOption(refreshUnreadCounts: boolean = true): Promise { + 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. * * @param {any} option The option to fetch data for. * @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} Promise resolved when done. */ - fetchDataForOption(option: any, loadingMore?: boolean): Promise { + fetchDataForOption(option: any, loadingMore?: boolean, refreshUnreadCounts: boolean = true): Promise { 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. + promises.push(this.messagesProvider.invalidateConversations().catch(() => { + // Shouldn't happen. + }).then(() => { + 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. + } + } + + return Promise.all(promises).then(() => { if (loadingMore) { option.conversations = option.conversations.concat(data.conversations); + 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); + }); + } } - option.unread = 0; // @todo. - option.canLoadMore = data.canLoadMore; }); } @@ -314,7 +382,12 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { * @return {Promise} Promise resolved when done. */ protected fetchConversationCounts(): Promise { - 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.individual.count = counts.individual; 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} 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. */ - protected findConversation(conversationId: number, userId?: number): any { + protected findConversation(conversationId: number, userId?: number, option?: any): any { if (conversationId) { - const conversations = (this.favourites.conversations || []).concat(this.group.conversations || []) - .concat(this.individual.conversations || []); + const conversations = option ? (option.conversations || []) : ((this.favourites.conversations || []) + .concat(this.group.conversations || []).concat(this.individual.conversations || [])); return conversations.find((conv) => { 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 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. */ @@ -358,9 +448,8 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { * @param {number} conversationId Conversation Id to load. * @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 {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.selectedUserId = userId; @@ -372,23 +461,6 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { params['message'] = messageId; } 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. * + * @param {any} option The option where the messages should be loaded. * @param {any[]} messages Offline messages. * @return {Promise} Promise resolved when done. */ - protected loadOfflineMessages(messages: any[]): Promise { + protected loadOfflineMessages(option: any, messages: any[]): Promise { const promises = []; messages.forEach((message) => { if (message.conversationid) { - // It's an existing conversation. Search it. - let conversation = this.findConversation(message.conversationid); + // It's an existing conversation. Search it in the current option. + let conversation = this.findConversation(message.conversationid, undefined, option); if (conversation) { // 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); } } 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.id = message.conversationid; - this.addLastOfflineMessage(conversation, message); - this.addOfflineConversation(conversation); + if (this.getConversationOption(conversation) == option) { + // Message belongs to current option, add the conversation. + this.addLastOfflineMessage(conversation, message); + this.addOfflineConversation(conversation); + } } - } else { - // Its 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); + } else if (option == this.individual) { + // 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; @@ -455,7 +531,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { this.addLastOfflineMessage(conversation, message); } } 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(() => { // User not found. }).then((user) => { @@ -523,18 +599,13 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { * @return {Promise} Promise resolved when done. */ refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise { + // Don't invalidate conversations and so, they always try to get latest data. 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(() => { + return this.fetchData(refreshUnreadCounts).finally(() => { if (refresher) { refresher.complete(); } @@ -552,7 +623,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { // Already expanded, close it. option.expanded = false; } 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. * * @param {any} option The option to expand. + * @param {booleam} [refreshUnreadCounts=true] Whether to refresh unread counts. + * @return {Promise} Promise resolved when done. */ - protected expandOption(option: any): void { + protected expandOption(option: any, refreshUnreadCounts: boolean = true): Promise { // Collapse all and expand the right one. this.favourites.expanded = false; this.group.expanded = false; this.individual.expanded = false; + 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; + }); } /** diff --git a/src/addon/messages/providers/messages.ts b/src/addon/messages/providers/messages.ts index 7b5cfe940..5b49d149c 100644 --- a/src/addon/messages/providers/messages.ts +++ b/src/addon/messages/providers/messages.ts @@ -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. * 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 {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). + * @param {number} [limitFrom=0] The offset to start at. * @param {string} [siteId] Site ID. If not defined, use current site. * @param {number} [userId] User ID. If not defined, current user in the site. * @return {Promise} Promise resolved with the conversations. @@ -966,13 +966,15 @@ export class AddonMessagesProvider { * Get conversation counts by type. * * @param {string} [siteId] Site ID. If not defined, use current site. - * @return {Promise} Promise resolved with favourite, individual and group conversation counts. + * @return {Promise} 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(), + cacheKey: this.getCacheKeyForConversationCounts() }; return site.read('core_message_get_conversation_counts', {}, preSets).then((result) => { @@ -1350,7 +1352,7 @@ export class AddonMessagesProvider { if (this.isGroupMessagingEnabled()) { // @since 3.6 const preSets = { - cacheKey: this.getCacheKeyForUnreadConversationCounts(), + cacheKey: this.getCacheKeyForUnreadConversationCounts() }; 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. * * @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} 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}> { + siteId = siteId || this.sitesProvider.getCurrentSiteId(); return this.invalidateUnreadConversationCounts(siteId).then(() => { From 79b67560ae7fa3a5e65540916feb7bcb1ed707e8 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 2 Jan 2019 16:37:45 +0100 Subject: [PATCH 3/5] MOBILE-2630 messages: Fix PTR issue in conversations --- .../group-conversations.html | 14 +++++----- .../group-conversations.ts | 28 +++++++++++++++++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/addon/messages/pages/group-conversations/group-conversations.html b/src/addon/messages/pages/group-conversations/group-conversations.html index f455f8428..e4d916c38 100644 --- a/src/addon/messages/pages/group-conversations/group-conversations.html +++ b/src/addon/messages/pages/group-conversations/group-conversations.html @@ -15,7 +15,7 @@ - + @@ -33,11 +33,11 @@ {{ 'core.favourites' | translate }} ({{ favourites.count }}) {{ favourites.unread }} -
+
- +

{{ 'addon.messages.nofavourites' | translate }}

@@ -52,11 +52,11 @@ {{ 'addon.messages.groupconversations' | translate }} ({{ group.count }}) {{ group.unread }} -
+
- +

{{ 'addon.messages.nogroupconversations' | translate }}

@@ -70,11 +70,11 @@ {{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }}) {{ individual.unread }} -
+
- +

{{ 'addon.messages.noindividualconversations' | translate }}

diff --git a/src/addon/messages/pages/group-conversations/group-conversations.ts b/src/addon/messages/pages/group-conversations/group-conversations.ts index acfa047f7..39be42305 100644 --- a/src/addon/messages/pages/group-conversations/group-conversations.ts +++ b/src/addon/messages/pages/group-conversations/group-conversations.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; import { IonicPage, Platform, NavController, NavParams, Content } from 'ionic-angular'; import { TranslateService } from '@ngx-translate/core'; import { CoreEventsProvider } from '@providers/events'; @@ -36,6 +36,9 @@ import { CoreUserProvider } from '@core/user/providers/user'; export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent; @ViewChild(Content) content: Content; + @ViewChild('favlist') favListEl: ElementRef; + @ViewChild('grouplist') groupListEl: ElementRef; + @ViewChild('indlist') indListEl: ElementRef; loaded = false; loadingMessage: string; @@ -61,6 +64,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { unread: 0 }; typeIndividual = AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL; + currentListEl: HTMLElement; protected loadingString: string; protected siteId: string; @@ -295,6 +299,8 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { 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; + + this.loadCurrentListElement(); } /** @@ -622,6 +628,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { if (option.expanded) { // Already expanded, close it. option.expanded = false; + this.loadCurrentListElement(); } else { this.expandOption(option).catch((error) => { this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true); @@ -645,7 +652,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { option.expanded = true; option.loading = true; - return this.fetchDataForOption(option, false, refreshUnreadCounts).catch((error) => { + return this.fetchDataForOption(option, false, refreshUnreadCounts).then(() => { + this.loadCurrentListElement(); + }).catch((error) => { option.expanded = false; return Promise.reject(error); @@ -654,6 +663,21 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { }); } + /** + * Load the current list element based on the expanded list. + */ + protected loadCurrentListElement(): void { + if (this.favourites.expanded) { + this.currentListEl = this.favListEl && this.favListEl.nativeElement; + } else if (this.group.expanded) { + this.currentListEl = this.groupListEl && this.groupListEl.nativeElement; + } else if (this.individual.expanded) { + this.currentListEl = this.indListEl && this.indListEl.nativeElement; + } else { + this.currentListEl = undefined; + } + } + /** * Navigate to the search page. */ From 01fd05a16858f29c5c2419bb6de3cc49c72b01f4 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 3 Jan 2019 08:37:33 +0100 Subject: [PATCH 4/5] MOBILE-2630 message: Always try to fetch contacts and requests --- .../confirmed-contacts/confirmed-contacts.ts | 19 +++++++++++++++---- .../contact-requests/contact-requests.ts | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/addon/messages/components/confirmed-contacts/confirmed-contacts.ts b/src/addon/messages/components/confirmed-contacts/confirmed-contacts.ts index f7efb6f76..528b48a9a 100644 --- a/src/addon/messages/components/confirmed-contacts/confirmed-contacts.ts +++ b/src/addon/messages/components/confirmed-contacts/confirmed-contacts.ts @@ -87,8 +87,20 @@ export class AddonMessagesConfirmedContactsComponent implements OnInit, OnDestro this.loadMoreError = false; const limitFrom = refresh ? 0 : this.contacts.length; + let promise; - return this.messagesProvider.getUserContacts(limitFrom).then((result) => { + if (limitFrom === 0) { + // Always try to get latest data from server. + promise = this.messagesProvider.invalidateUserContacts().catch(() => { + // Shouldn't happen. + }); + } else { + promise = Promise.resolve(); + } + + return promise.then(() => { + return this.messagesProvider.getUserContacts(limitFrom); + }).then((result) => { this.contacts = refresh ? result.contacts : this.contacts.concat(result.contacts); this.canLoadMore = result.canLoadMore; }).catch((error) => { @@ -104,9 +116,8 @@ export class AddonMessagesConfirmedContactsComponent implements OnInit, OnDestro * @return {Promise} Promise resolved when done. */ refreshData(refresher?: any): Promise { - return this.messagesProvider.invalidateUserContacts().then(() => { - return this.fetchData(true); - }).finally(() => { + // No need to invalidate contacts, we always try to get the latest. + return this.fetchData(true).finally(() => { refresher && refresher.complete(); }); } diff --git a/src/addon/messages/components/contact-requests/contact-requests.ts b/src/addon/messages/components/contact-requests/contact-requests.ts index 854bd90bb..4a77bfdd1 100644 --- a/src/addon/messages/components/contact-requests/contact-requests.ts +++ b/src/addon/messages/components/contact-requests/contact-requests.ts @@ -78,8 +78,20 @@ export class AddonMessagesContactRequestsComponent implements OnInit, OnDestroy this.loadMoreError = false; const limitFrom = refresh ? 0 : this.requests.length; + let promise; - return this.messagesProvider.getContactRequests(limitFrom).then((result) => { + if (limitFrom === 0) { + // Always try to get latest data from server. + promise = this.messagesProvider.invalidateContactRequestsCache().catch(() => { + // Shouldn't happen. + }); + } else { + promise = Promise.resolve(); + } + + return promise.then(() => { + return this.messagesProvider.getContactRequests(limitFrom); + }).then((result) => { this.requests = refresh ? result.requests : this.requests.concat(result.requests); this.canLoadMore = result.canLoadMore; }).catch((error) => { @@ -98,9 +110,8 @@ export class AddonMessagesContactRequestsComponent implements OnInit, OnDestroy // Refresh the number of contacts requests to update badges. this.messagesProvider.refreshContactRequestsCount(); - return this.messagesProvider.invalidateContactRequestsCache().then(() => { - return this.fetchData(true); - }).finally(() => { + // No need to invalidate contact requests, we always try to get the latest. + return this.fetchData(true).finally(() => { refresher && refresher.complete(); }); } From 4385952fc252813bcf48cf207c9308b113299173 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 3 Jan 2019 09:49:23 +0100 Subject: [PATCH 5/5] MOBILE-2630 messages: Refresh contacts when request accepted --- .../messages/components/contacts/contacts.ts | 16 ++++++++++++++++ .../messages/pages/discussion/discussion.ts | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/addon/messages/components/contacts/contacts.ts b/src/addon/messages/components/contacts/contacts.ts index 4a23cc2d7..8df67aabb 100644 --- a/src/addon/messages/components/contacts/contacts.ts +++ b/src/addon/messages/components/contacts/contacts.ts @@ -47,6 +47,8 @@ export class AddonMessagesContactsComponent { }; searchString = ''; + protected memberInfoObserver; + constructor(sitesProvider: CoreSitesProvider, translate: TranslateService, private appProvider: CoreAppProvider, private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams, private eventsProvider: CoreEventsProvider) { @@ -58,6 +60,13 @@ export class AddonMessagesContactsComponent { this.loadingMessage = this.loadingMessages; this.discussionUserId = navParams.get('discussionUserId') || false; + + // Refresh the list when a contact request is confirmed. + this.memberInfoObserver = eventsProvider.on(AddonMessagesProvider.MEMBER_INFO_CHANGED_EVENT, (data) => { + if (data.contactRequestConfirmed) { + this.refreshData(); + } + }, sitesProvider.getCurrentSiteId()); } /** @@ -217,4 +226,11 @@ export class AddonMessagesContactsComponent { }; this.eventsProvider.trigger(AddonMessagesProvider.SPLIT_VIEW_LOAD_EVENT, params, this.siteId); } + + /** + * Component destroyed. + */ + ngOnDestroy(): void { + this.memberInfoObserver && this.memberInfoObserver.off(); + } } diff --git a/src/addon/messages/pages/discussion/discussion.ts b/src/addon/messages/pages/discussion/discussion.ts index 6b94fe915..7ac5d20b7 100644 --- a/src/addon/messages/pages/discussion/discussion.ts +++ b/src/addon/messages/pages/discussion/discussion.ts @@ -223,7 +223,12 @@ export class AddonMessagesDiscussionPage implements OnDestroy { } if (this.userId) { - promises.push(this.messagesProvider.getMemberInfo(this.userId).then((member) => { + // Get the member info. Invalidate first to make sure we get the latest status. + promises.push(this.messagesProvider.invalidateMemberInfo(this.userId).catch(() => { + // Shouldn't happen. + }).then(() => { + return this.messagesProvider.getMemberInfo(this.userId); + }).then((member) => { this.otherMember = member; if (!exists && member) { this.conversationImage = member.profileimageurl;