diff --git a/src/addon/messages/components/components.module.ts b/src/addon/messages/components/components.module.ts
index 5d81ea357..270ed0e3a 100644
--- a/src/addon/messages/components/components.module.ts
+++ b/src/addon/messages/components/components.module.ts
@@ -20,10 +20,12 @@ import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives';
import { CorePipesModule } from '@pipes';
import { AddonMessagesDiscussionsComponent } from '../components/discussions/discussions';
+import { AddonMessagesContactsComponent } from '../components/contacts/contacts';
@NgModule({
declarations: [
AddonMessagesDiscussionsComponent,
+ AddonMessagesContactsComponent
],
imports: [
CommonModule,
@@ -37,6 +39,7 @@ import { AddonMessagesDiscussionsComponent } from '../components/discussions/dis
],
exports: [
AddonMessagesDiscussionsComponent,
+ AddonMessagesContactsComponent
]
})
export class AddonMessagesComponentsModule {}
diff --git a/src/addon/messages/components/contacts/contacts.html b/src/addon/messages/components/contacts/contacts.html
new file mode 100644
index 000000000..67cf29fc9
--- /dev/null
+++ b/src/addon/messages/components/contacts/contacts.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0 || contactType === searchType)">
+
+ {{ 'addon.messages.type_' + contactType | translate }}
+ {{ contacts[contactType].length }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/addon/messages/components/contacts/contacts.scss b/src/addon/messages/components/contacts/contacts.scss
new file mode 100644
index 000000000..ff39202e3
--- /dev/null
+++ b/src/addon/messages/components/contacts/contacts.scss
@@ -0,0 +1,12 @@
+addon-messages-discussions {
+ h2 {
+ display: flex;
+ justify-content: space-between;
+
+ .note {
+ margin: 0;
+ align-self: flex-end;
+ display: inline-flex;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/addon/messages/components/contacts/contacts.ts b/src/addon/messages/components/contacts/contacts.ts
new file mode 100644
index 000000000..781c20b29
--- /dev/null
+++ b/src/addon/messages/components/contacts/contacts.ts
@@ -0,0 +1,225 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Component } from '@angular/core';
+import { NavParams } from 'ionic-angular';
+import { TranslateService } from '@ngx-translate/core';
+import { CoreSitesProvider } from '@providers/sites';
+import { AddonMessagesProvider } from '../../providers/messages';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
+import { CoreUtilsProvider } from '@providers/utils/utils';
+import { CoreAppProvider } from '@providers/app';
+import { CoreEventsProvider } from '@providers/events';
+
+/**
+ * Component that displays the list of contacts.
+ */
+@Component({
+ selector: 'addon-messages-contacts',
+ templateUrl: 'contacts.html',
+})
+export class AddonMessagesContactsComponent {
+
+ protected currentUserId: number;
+ protected searchingMessages: string;
+ protected loadingMessages: string;
+ protected siteId: string;
+ protected noSearchTypes = ['online', 'offline', 'blocked', 'strangers'];
+
+ loaded = false;
+ discussionUserId: number;
+ contactTypes = this.noSearchTypes;
+ searchType = 'search';
+ loadingMessage = '';
+ hasContacts = false;
+ contacts = {
+ search: []
+ };
+ searchString = '';
+
+ constructor(sitesProvider: CoreSitesProvider, translate: TranslateService, private appProvider: CoreAppProvider,
+ private messagesProvider: AddonMessagesProvider, private domUtils: CoreDomUtilsProvider, navParams: NavParams,
+ private eventsProvider: CoreEventsProvider) {
+
+ this.currentUserId = sitesProvider.getCurrentSiteUserId();
+ this.siteId = sitesProvider.getCurrentSiteId();
+ this.searchingMessages = translate.instant('core.searching');
+ this.loadingMessages = translate.instant('core.loading');
+ this.loadingMessage = this.loadingMessages;
+
+ this.discussionUserId = navParams.get('discussionUserId') || false;
+ }
+
+ /**
+ * Component loaded.
+ */
+ ngOnInit(): void {
+ if (this.discussionUserId) {
+ // There is a discussion to load, open the discussion in a new state.
+ this.gotoDiscussion(this.discussionUserId);
+ }
+
+ this.fetchData().then(() => {
+ if (!this.discussionUserId && this.hasContacts) {
+ let contact;
+ for (const x in this.contacts) {
+ if (this.contacts[x].length > 0) {
+ contact = this.contacts[x][0];
+ break;
+ }
+ }
+
+ if (contact) {
+ // Take first and load it.
+ this.gotoDiscussion(contact.id, true);
+ }
+ }
+ }).finally(() => {
+ this.loaded = true;
+ });
+ }
+
+ /**
+ * Refresh the data.
+ *
+ * @param {any} [refresher] Refresher.
+ * @return {Promise} Promise resolved when done.
+ */
+ refreshData(refresher?: any): Promise {
+ let promise;
+
+ if (this.searchString) {
+ // User has searched, update the search.
+ promise = this.performSearch(this.searchString);
+ } else {
+ // Update contacts.
+ promise = this.messagesProvider.invalidateAllContactsCache(this.currentUserId).then(() => {
+ return this.fetchData();
+ });
+ }
+
+ return promise.finally(() => {
+ refresher.complete();
+ });
+ }
+
+ /**
+ * Fetch contacts.
+ *
+ * @return {Promise} Promise resolved when done.
+ */
+ protected fetchData(): Promise {
+ this.loadingMessage = this.loadingMessages;
+
+ return this.messagesProvider.getAllContacts().then((contacts) => {
+ for (const x in contacts) {
+ if (contacts[x].length > 0) {
+ this.contacts[x] = this.sortUsers(contacts[x]);
+ } else {
+ this.contacts[x] = [];
+ }
+ }
+
+ this.clearSearch();
+ }).catch((error) => {
+ this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingcontacts', true);
+
+ return Promise.reject(null);
+ });
+ }
+
+ /**
+ * Sort user list by fullname
+ * @param {any[]} list List to sort.
+ * @return {any[]} Sorted list.
+ */
+ protected sortUsers(list: any[]): any[] {
+ return list.sort((a, b) => {
+ const compareA = a.fullname.toLowerCase(),
+ compareB = b.fullname.toLowerCase();
+
+ return compareA.localeCompare(compareB);
+ });
+ }
+
+ /**
+ * Clear search and show all contacts again.
+ */
+ clearSearch(): void {
+ this.searchString = ''; // Reset searched string.
+ this.contactTypes = this.noSearchTypes;
+
+ this.hasContacts = false;
+ for (const x in this.contacts) {
+ if (this.contacts[x].length > 0) {
+ this.hasContacts = true;
+
+ return;
+ }
+ }
+ }
+
+ /**
+ * Search users from the UI.
+ *
+ * @param {string} query Text to search for.
+ * @return {Promise} Resolved when done.
+ */
+ search(query: string): Promise {
+ this.appProvider.closeKeyboard();
+
+ this.loaded = false;
+ this.loadingMessage = this.searchingMessages;
+
+ return this.performSearch(query).finally(() => {
+ this.loaded = true;
+ });
+ }
+
+ /**
+ * Perform the search of users.
+ *
+ * @param {string} query Text to search for.
+ * @return {Promise} Resolved when done.
+ */
+ protected performSearch(query: string): Promise {
+ return this.messagesProvider.searchContacts(query).then((result) => {
+ this.hasContacts = result.length > 0;
+ this.searchString = query;
+ this.contactTypes = ['search'];
+
+ this.contacts['search'] = this.sortUsers(result);
+ }).catch((error) => {
+ this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingcontacts', true);
+
+ return Promise.reject(null);
+ });
+ }
+
+ /**
+ * Navigate to a particular discussion.
+ *
+ * @param {number} discussionUserId Discussion Id to load.
+ * @param {boolean} [onlyWithSplitView=false] Only go to Discussion if split view is on.
+ */
+ gotoDiscussion(discussionUserId: number, onlyWithSplitView: boolean = false): void {
+ this.discussionUserId = discussionUserId;
+
+ const params = {
+ discussion: discussionUserId,
+ onlyWithSplitView: onlyWithSplitView
+ };
+ this.eventsProvider.trigger(AddonMessagesProvider.SPLIT_VIEW_LOAD_EVENT, params, this.siteId);
+ }
+}
diff --git a/src/addon/messages/components/discussions/discussions.html b/src/addon/messages/components/discussions/discussions.html
index d7ef201cd..c33cb5ef0 100644
--- a/src/addon/messages/components/discussions/discussions.html
+++ b/src/addon/messages/components/discussions/discussions.html
@@ -3,7 +3,7 @@
-
+
@@ -15,9 +15,6 @@
{{ 'core.searchresults' | translate }}
{{ search.results.length }}
-
diff --git a/src/addon/messages/components/discussions/discussions.ts b/src/addon/messages/components/discussions/discussions.ts
index ec31793dc..0d5a1fb4e 100644
--- a/src/addon/messages/components/discussions/discussions.ts
+++ b/src/addon/messages/components/discussions/discussions.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, OnDestroy, ViewChild } from '@angular/core';
+import { Component, OnDestroy } from '@angular/core';
import { Platform, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
@@ -190,6 +190,7 @@ export class AddonMessagesDiscussionsComponent implements OnDestroy {
clearSearch(): void {
this.loaded = false;
this.search.showResults = false;
+ this.search.text = ''; // Reset searched string.
this.fetchData().finally(() => {
this.loaded = true;
});
diff --git a/src/addon/messages/lang/en.json b/src/addon/messages/lang/en.json
index 1972d107d..c8c5a4985 100644
--- a/src/addon/messages/lang/en.json
+++ b/src/addon/messages/lang/en.json
@@ -1,5 +1,7 @@
{
"blocknoncontacts": "Prevent non-contacts from messaging me",
+ "contactlistempty": "The contact list is empty",
+ "contactname": "Contact name",
"contacts": "Contacts",
"deletemessage": "Delete message",
"deletemessageconfirmation": "Are you sure you want to delete this message? It will only be deleted from your messaging history and will still be viewable by the user who sent or received the message.",
@@ -13,5 +15,11 @@
"newmessage": "New message",
"newmessages": "New messages",
"nomessages": "No messages",
+ "nousersfound": "No users found",
+ "type_blocked": "Blocked",
+ "type_offline": "Offline",
+ "type_online": "Online",
+ "type_search": "Search results",
+ "type_strangers": "Others",
"warningmessagenotsent": "Couldn't send message(s) to user {{user}}. {{error}}"
}
\ No newline at end of file
diff --git a/src/addon/messages/pages/discussion/discussion.html b/src/addon/messages/pages/discussion/discussion.html
index 3b2e2db08..f41c4d1de 100644
--- a/src/addon/messages/pages/discussion/discussion.html
+++ b/src/addon/messages/pages/discussion/discussion.html
@@ -44,8 +44,8 @@
-
+