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",