From f22f33dad4821ab41f49eee4942b1cf61f2258d4 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 28 Nov 2018 11:25:25 +0100 Subject: [PATCH] MOBILE-2631 message: Allow adding/removing favourites --- scripts/langindex.json | 2 + src/addon/messages/lang/en.json | 2 + .../messages/pages/discussion/discussion.html | 6 +- .../messages/pages/discussion/discussion.ts | 116 ++++++++++++------ .../group-conversations.ts | 15 ++- src/addon/messages/providers/messages.ts | 50 +++++++- src/assets/lang/en.json | 2 + 7 files changed, 150 insertions(+), 43 deletions(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index 9f1566add..4f57c5479 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -148,6 +148,7 @@ "addon.files.sitefiles": "moodle", "addon.messageoutput_airnotifier.processorsettingsdesc": "local_moodlemobileapp", "addon.messages.addcontact": "message", + "addon.messages.addtofavourites": "message", "addon.messages.blocknoncontacts": "message", "addon.messages.blockuser": "message", "addon.messages.blockuserconfirm": "message", @@ -181,6 +182,7 @@ "addon.messages.numparticipants": "message", "addon.messages.removecontact": "message", "addon.messages.removecontactconfirm": "local_moodlemobileapp", + "addon.messages.removefromfavourites": "message", "addon.messages.showdeletemessages": "local_moodlemobileapp", "addon.messages.type_blocked": "local_moodlemobileapp", "addon.messages.type_offline": "local_moodlemobileapp", diff --git a/src/addon/messages/lang/en.json b/src/addon/messages/lang/en.json index a95948ee2..b494638c7 100644 --- a/src/addon/messages/lang/en.json +++ b/src/addon/messages/lang/en.json @@ -1,5 +1,6 @@ { "addcontact": "Add contact", + "addtofavourites": "Star", "blocknoncontacts": "Prevent non-contacts from messaging me", "blockuser": "Block user", "blockuserconfirm": "Are you sure you want to block {{$a}}?", @@ -33,6 +34,7 @@ "numparticipants": "{{$a}} participants", "removecontact": "Remove contact", "removecontactconfirm": "Contact will be removed from your contacts list.", + "removefromfavourites": "Unstar", "showdeletemessages": "Show delete messages", "type_blocked": "Blocked", "type_offline": "Offline", diff --git a/src/addon/messages/pages/discussion/discussion.html b/src/addon/messages/pages/discussion/discussion.html index 0629928fc..1dbde4d4c 100644 --- a/src/addon/messages/pages/discussion/discussion.html +++ b/src/addon/messages/pages/discussion/discussion.html @@ -3,14 +3,16 @@ + - - + + + diff --git a/src/addon/messages/pages/discussion/discussion.ts b/src/addon/messages/pages/discussion/discussion.ts index 7cbe7df9f..13c0ec5d7 100644 --- a/src/addon/messages/pages/discussion/discussion.ts +++ b/src/addon/messages/pages/discussion/discussion.ts @@ -75,6 +75,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy { groupMessagingEnabled: boolean; isGroup = false; members: any = {}; // Members that wrote a message, indexed by ID. + favouriteIcon = 'fa-star'; constructor(private eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, navParams: NavParams, private userProvider: CoreUserProvider, private navCtrl: NavController, private messagesSync: AddonMessagesSyncProvider, @@ -332,51 +333,67 @@ export class AddonMessagesDiscussionPage implements OnDestroy { * @return {Promise} Promise resolved with a boolean: whether the conversation exists or not. */ protected getConversation(conversationId: number, userId: number): Promise { - let promise; + let promise, + fallbackConversation; + // Try to get the conversationId if we don't have it. if (conversationId) { - // Retrieve the conversation. Invalidate data first to get the right unreadcount. - promise = this.messagesProvider.invalidateConversation(conversationId).then(() => { - return this.messagesProvider.getConversation(conversationId); - }); + promise = Promise.resolve(conversationId); } else { - // We don't have the conversation ID, check if it exists. - promise = this.messagesProvider.getConversationBetweenUsers(userId).catch((error) => { + promise = this.messagesProvider.getConversationBetweenUsers(userId).then((conversation) => { + fallbackConversation = conversation; - // Probably conversation does not exist or user is offline. Try to load offline messages. - return this.messagesOffline.getMessages(userId).then((messages) => { - if (messages && messages.length) { - // We have offline messages, this probably means that the conversation didn't exist. Don't display error. - messages.forEach((message) => { - message.pending = true; - message.text = message.smallmessage; - }); - - this.loadMessages(messages); - } else if (error.errorcode != 'errorconversationdoesnotexist') { - // Display the error. - return Promise.reject(error); - } - }); + return conversation.id; }); } - return promise.then((conversation) => { - this.conversation = conversation; - - if (conversation) { - this.conversationId = conversation.id; - this.title = conversation.name; - this.conversationImage = conversation.imageurl; - this.isGroup = conversation.type == AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP; - if (!this.isGroup) { - this.userId = conversation.userid; + return promise.then((conversationId) => { + // Retrieve the conversation. Invalidate data first to get the right unreadcount. + return this.messagesProvider.invalidateConversation(conversationId).catch(() => { + // Ignore errors. + }).then(() => { + return this.messagesProvider.getConversation(conversationId); + }).catch((error) => { + // Get conversation failed, use the fallback one if we have it. + if (fallbackConversation) { + return fallbackConversation; } - return true; - } else { - return false; - } + return Promise.reject(error); + }).then((conversation) => { + this.conversation = conversation; + + if (conversation) { + this.conversationId = conversation.id; + this.title = conversation.name; + this.conversationImage = conversation.imageurl; + this.isGroup = conversation.type == AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP; + this.favouriteIcon = conversation.isfavourite ? 'fa-star-o' : 'fa-star'; + if (!this.isGroup) { + this.userId = conversation.userid; + } + + return true; + } else { + return false; + } + }); + }, (error) => { + // Probably conversation does not exist or user is offline. Try to load offline messages. + return this.messagesOffline.getMessages(userId).then((messages) => { + if (messages && messages.length) { + // We have offline messages, this probably means that the conversation didn't exist. Don't display error. + messages.forEach((message) => { + message.pending = true; + message.text = message.smallmessage; + }); + + this.loadMessages(messages); + } else if (error.errorcode != 'errorconversationdoesnotexist') { + // Display the error. + return Promise.reject(error); + } + }); }); } @@ -940,6 +957,33 @@ export class AddonMessagesDiscussionPage implements OnDestroy { } } + /** + * Change the favourite state of the current conversation. + * + * @param {Function} [done] Function to call when done. + */ + changeFavourite(done?: () => void): void { + this.favouriteIcon = 'spinner'; + + this.messagesProvider.setFavouriteConversation(this.conversation.id, !this.conversation.isfavourite).then(() => { + this.conversation.isfavourite = !this.conversation.isfavourite; + + // Get the conversation data so it's cached. Don't block the user for this. + this.messagesProvider.getConversation(this.conversation.id); + + this.eventsProvider.trigger(AddonMessagesProvider.UPDATE_CONVERSATION_LIST_EVENT, { + conversationId: this.conversation.id, + action: 'favourite', + value: this.conversation.isfavourite + }, this.siteId); + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'Error changing favourite state.'); + }).finally(() => { + this.favouriteIcon = this.conversation.isfavourite ? 'fa-star-o' : 'fa-star'; + done && done(); + }); + } + /** * Page destroyed. */ diff --git a/src/addon/messages/pages/group-conversations/group-conversations.ts b/src/addon/messages/pages/group-conversations/group-conversations.ts index 2c8cf2adc..2b9239741 100644 --- a/src/addon/messages/pages/group-conversations/group-conversations.ts +++ b/src/addon/messages/pages/group-conversations/group-conversations.ts @@ -73,6 +73,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { protected readChangedObserver: any; protected cronObserver: any; protected openConversationObserver: any; + protected updateConversationListObserver: any; constructor(private eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, translate: TranslateService, private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams, @@ -115,22 +116,22 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { } }, this.siteId); - // Update discussions when a message is read. + // Update conversations when a message is read. this.readChangedObserver = eventsProvider.on(AddonMessagesProvider.READ_CHANGED_EVENT, (data) => { if (data.conversationId) { const conversation = this.findConversation(data.conversationId); if (typeof conversation != 'undefined') { - // A discussion has been read reset counter. + // A conversation has been read reset counter. conversation.unreadcount = 0; - // Discussions changed, invalidate them. + // Conversations changed, invalidate them. this.messagesProvider.invalidateConversations(); } } }, this.siteId); - // Update discussions when cron read is executed. + // Update conversations when cron read is executed. this.cronObserver = eventsProvider.on(AddonMessagesProvider.READ_CRON_EVENT, (data) => { this.refreshData(); }, this.siteId); @@ -153,6 +154,11 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { }); }); + // Update conversations if we receive an event to do so. + this.updateConversationListObserver = eventsProvider.on(AddonMessagesProvider.UPDATE_CONVERSATION_LIST_EVENT, () => { + this.refreshData(); + }, this.siteId); + // If a message push notification is received, refresh the view. this.pushObserver = pushNotificationsDelegate.on('receive').subscribe((notification) => { // New message received. If it's from current site, refresh the data. @@ -551,5 +557,6 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy { this.readChangedObserver && this.readChangedObserver.off(); this.cronObserver && this.cronObserver.off(); this.openConversationObserver && this.openConversationObserver.off(); + this.updateConversationListObserver && this.updateConversationListObserver.off(); } } diff --git a/src/addon/messages/providers/messages.ts b/src/addon/messages/providers/messages.ts index eeae588bb..8e160d4d4 100644 --- a/src/addon/messages/providers/messages.ts +++ b/src/addon/messages/providers/messages.ts @@ -35,6 +35,7 @@ export class AddonMessagesProvider { 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 POLL_INTERVAL = 10000; static PUSH_SIMULATION_COMPONENT = 'AddonMessagesPushSimulation'; @@ -1114,7 +1115,7 @@ export class AddonMessagesProvider { return this.sitesProvider.getSite(siteId).then((site) => { userId = userId || site.getUserId(); - return site.invalidateWsCacheForKey(this.getCacheKeyForConversation(conversationId, userId)); + return site.invalidateWsCacheForKey(this.getCacheKeyForConversation(userId, conversationId)); }); } @@ -1697,6 +1698,53 @@ export class AddonMessagesProvider { }); } + /** + * Set or unset a conversation as favourite. + * + * @param {number} conversationId Conversation ID. + * @param {boolean} set Whether to set or unset it as favourite. + * @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} Resolved when done. + */ + setFavouriteConversation(conversationId: number, set: boolean, siteId?: string, userId?: number): Promise { + return this.setFavouriteConversations([conversationId], set, siteId, userId); + } + + /** + * Set or unset some conversations as favourites. + * + * @param {number[]} conversations Conversation IDs. + * @param {boolean} set Whether to set or unset them as favourites. + * @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} Resolved when done. + */ + setFavouriteConversations(conversations: number[], set: boolean, siteId?: string, userId?: number): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + userId = userId || site.getUserId(); + + const params = { + userid: userId, + conversations: conversations + }, + wsName = set ? 'core_message_set_favourite_conversations' : 'core_message_unset_favourite_conversations'; + + return site.write(wsName, params).then(() => { + // Invalidate the conversations data. + const promises = []; + + conversations.forEach((conversationId) => { + promises.push(this.invalidateConversation(conversationId, site.getId(), userId)); + }); + + return Promise.all(promises).catch(() => { + // Ignore errors. + }); + }); + }); + } + /** * Helper method to sort conversations by last message time. * diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 810196869..e42dcf18d 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -148,6 +148,7 @@ "addon.files.sitefiles": "Site files", "addon.messageoutput_airnotifier.processorsettingsdesc": "Configure devices", "addon.messages.addcontact": "Add contact", + "addon.messages.addtofavourites": "Star", "addon.messages.blocknoncontacts": "Prevent non-contacts from messaging me", "addon.messages.blockuser": "Block user", "addon.messages.blockuserconfirm": "Are you sure you want to block {{$a}}?", @@ -181,6 +182,7 @@ "addon.messages.numparticipants": "{{$a}} participants", "addon.messages.removecontact": "Remove contact", "addon.messages.removecontactconfirm": "Contact will be removed from your contacts list.", + "addon.messages.removefromfavourites": "Unstar", "addon.messages.showdeletemessages": "Show delete messages", "addon.messages.type_blocked": "Blocked", "addon.messages.type_offline": "Offline",