MOBILE-3631 messages: Add contacts page

main
Pau Ferrer Ocaña 2021-01-21 16:34:47 +01:00
parent 99448a3054
commit 04c6f4480d
12 changed files with 753 additions and 1 deletions

View File

@ -16,6 +16,7 @@ import { Injector, NgModule } from '@angular/core';
import { RouterModule, ROUTES, Routes } from '@angular/router';
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
import { AddonMessagesContactsRoutingModule } from './pages/contacts/messages-contacts-routing.module';
import { AddonMessagesIndexRoutingModule } from './pages/index-35/messages-index-routing.module';
function buildRoutes(injector: Injector): Routes {
@ -34,6 +35,11 @@ function buildRoutes(injector: Injector): Routes {
loadChildren: () => import('./pages/search/search.module')
.then(m => m.AddonMessagesSearchPageModule),
},
{
path: 'contacts', // 3.6 or greater.
loadChildren: () => import('./pages/contacts/contacts.module')
.then(m => m.AddonMessagesContactsPageModule),
},
...buildTabMainRoutes(injector, {
redirectTo: 'index',
pathMatch: 'full',
@ -53,8 +59,25 @@ const indexTabRoutes: Routes = [
},
];
// 3.6 or greater.
const contactsTabRoutes: Routes = [
{
path: 'confirmed',
loadChildren: () => import('./pages/contacts-confirmed/contacts-confirmed.module')
.then(m => m.AddonMessagesContactsConfirmedPageModule),
},
{
path: 'requests',
loadChildren: () => import('./pages/contacts-requests/contacts-requests.module')
.then(m => m.AddonMessagesContactsRequestsPageModule),
},
];
@NgModule({
imports: [AddonMessagesIndexRoutingModule.forChild({ children: indexTabRoutes })],
imports: [
AddonMessagesIndexRoutingModule.forChild({ children: indexTabRoutes }),
AddonMessagesContactsRoutingModule.forChild({ children: contactsTabRoutes }),
],
exports: [RouterModule],
providers: [
{

View File

@ -0,0 +1,30 @@
<ion-content>
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded" class="core-loading-center">
<ion-list class="ion-no-margin">
<ion-item class="ion-text-wrap" *ngFor="let contact of contacts" [title]="contact.fullname"
(click)="selectUser(contact.id)"
[class.core-split-item-selected]="contact.id == selectedUserId" class="addon-messages-conversation-item">
<core-user-avatar slot="start" core-user-avatar [user]="contact" [checkOnline]="contact.showonlinestatus"
[linkProfile]="false"></core-user-avatar>
<ion-label>
<h2>
{{ contact.fullname }}
<ion-icon *ngIf="contact.isblocked" name="fas-user-slash" slot="end">
</ion-icon>
</h2>
</ion-label>
</ion-item>
</ion-list>
<core-empty-box *ngIf="!contacts.length" icon="far-address-book"
[message]="'addon.messages.nocontactsgetstarted' | translate">
</core-empty-box>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError"
position="bottom">
</core-infinite-loading>
</core-loading>
</ion-content>

View File

@ -0,0 +1,45 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { RouterModule, Routes } from '@angular/router';
import { CommonModule } from '@angular/common';
import { CoreSharedModule } from '@/core/shared.module';
import { AddonMessagesContactsConfirmedPage } from './contacts-confirmed.page';
const routes: Routes = [
{
path: '',
component: AddonMessagesContactsConfirmedPage,
},
];
@NgModule({
imports: [
RouterModule.forChild(routes),
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreSharedModule,
],
declarations: [
AddonMessagesContactsConfirmedPage,
],
exports: [RouterModule],
})
export class AddonMessagesContactsConfirmedPageModule {}

View File

@ -0,0 +1,165 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, OnDestroy, OnInit } from '@angular/core';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites';
import {
AddonMessagesProvider,
AddonMessagesConversationMember,
AddonMessages,
AddonMessagesMemberInfoChangedEventData,
AddonMessagesSplitViewLoadContactsEventData,
} from '../../services/messages';
import { CoreDomUtils } from '@services/utils/dom';
import { IonRefresher } from '@ionic/angular';
import { CoreNavigator } from '@services/navigator';
/**
* Component that displays the list of confirmed contacts.
*/
@Component({
selector: 'addon-messages-confirmed-contacts',
templateUrl: 'contacts-confirmed.html',
})
export class AddonMessagesContactsConfirmedPage implements OnInit, OnDestroy {
loaded = false;
canLoadMore = false;
loadMoreError = false;
contacts: AddonMessagesConversationMember[] = [];
selectedUserId?: number;
protected memberInfoObserver: CoreEventObserver;
constructor() {
// this.onUserSelected = new EventEmitter();
// Update block status of a user.
this.memberInfoObserver = CoreEvents.on<AddonMessagesMemberInfoChangedEventData>(
AddonMessagesProvider.MEMBER_INFO_CHANGED_EVENT,
(data) => {
if (data.userBlocked || data.userUnblocked) {
const user = this.contacts.find((user) => user.id == data.userId);
if (user) {
user.isblocked = !!data.userBlocked;
}
} else if (data.contactRemoved) {
const index = this.contacts.findIndex((contact) => contact.id == data.userId);
if (index >= 0) {
this.contacts.splice(index, 1);
}
} else if (data.contactRequestConfirmed) {
this.refreshData();
}
},
CoreSites.instance.getCurrentSiteId(),
);
}
/**
* Component loaded.
*/
async ngOnInit(): Promise<void> {
try {
await this.fetchData();
if (this.contacts.length) {
this.selectUser(this.contacts[0].id, true);
}
} finally {
this.loaded = true;
}
// Workaround for infinite scrolling.
// @todo this.content.resize();
}
/**
* Fetch contacts.
*
* @param refresh True if we are refreshing contacts, false if we are loading more.
* @return Promise resolved when done.
*/
async fetchData(refresh: boolean = false): Promise<void> {
this.loadMoreError = false;
const limitFrom = refresh ? 0 : this.contacts.length;
if (limitFrom === 0) {
// Always try to get latest data from server.
await AddonMessages.instance.invalidateUserContacts();
}
try {
const result = await AddonMessages.instance.getUserContacts(limitFrom);
this.contacts = refresh ? result.contacts : this.contacts.concat(result.contacts);
this.canLoadMore = result.canLoadMore;
} catch (error) {
this.loadMoreError = true;
CoreDomUtils.instance.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingcontacts', true);
}
}
/**
* Refresh contacts.
*
* @param refresher Refresher.
* @return Promise resolved when done.
*/
async refreshData(refresher?: CustomEvent<IonRefresher>): Promise<void> {
// No need to invalidate contacts, we always try to get the latest.
await this.fetchData(true).finally(() => {
refresher?.detail.complete();
});
}
/**
* Load more contacts.
*
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
* @return Resolved when done.
*/
async loadMore(infiniteComplete?: () => void): Promise<void> {
await this.fetchData().finally(() => {
infiniteComplete && infiniteComplete();
});
}
/**
* Notify that a contact has been selected.
*
* @param userId User id.
* @param onInit Whether the contact is selected on initial load.
*/
selectUser(userId: number, onInit: boolean = false): void {
this.selectedUserId = userId;
const data: AddonMessagesSplitViewLoadContactsEventData = {
userId,
onInit,
};
CoreEvents.trigger(AddonMessagesProvider.SPLIT_VIEW_LOAD_CONTACTS_EVENT, data);
// @todo: Check if split view is visible before
CoreNavigator.instance.navigateToSitePath('discussion', { params : { userId } });
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.memberInfoObserver?.off();
}
}

View File

@ -0,0 +1,24 @@
<ion-content>
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded" class="core-loading-center">
<ion-list class="ion-no-margin">
<ion-item class="ion-text-wrap" *ngFor="let request of requests" [title]="request.fullname"
(click)="selectUser(request.id)" [class.core-split-item-selected]="request.id == selectedUserId"
class="addon-messages-conversation-item">
<core-user-avatar slot="start" [user]="request" [linkProfile]="false"></core-user-avatar>
<ion-label>
<h2>{{ request.fullname }}</h2>
<p *ngIf="!request.iscontact">
{{ 'addon.messages.wouldliketocontactyou' | translate }}
</p>
</ion-label>
</ion-item>
</ion-list>
<core-empty-box *ngIf="!requests.length" icon="far-address-book" [message]="'addon.messages.nocontactrequests' | translate">
</core-empty-box>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError" position="bottom">
</core-infinite-loading>
</core-loading>
</ion-content>

View File

@ -0,0 +1,45 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { RouterModule, Routes } from '@angular/router';
import { CommonModule } from '@angular/common';
import { CoreSharedModule } from '@/core/shared.module';
import { AddonMessagesContactsRequestsPage } from './contacts-requests.page';
const routes: Routes = [
{
path: '',
component: AddonMessagesContactsRequestsPage,
},
];
@NgModule({
imports: [
RouterModule.forChild(routes),
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreSharedModule,
],
declarations: [
AddonMessagesContactsRequestsPage,
],
exports: [RouterModule],
})
export class AddonMessagesContactsRequestsPageModule {}

View File

@ -0,0 +1,161 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, OnDestroy, OnInit } from '@angular/core';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites';
import {
AddonMessagesProvider,
AddonMessagesConversationMember,
AddonMessagesSplitViewLoadContactsEventData,
AddonMessages,
AddonMessagesMemberInfoChangedEventData,
} from '../../services/messages';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreNavigator } from '@services/navigator';
import { IonRefresher } from '@ionic/angular';
/**
* Component that displays the list of contact requests.
*/
@Component({
selector: 'addon-messages-contact-requests',
templateUrl: 'contacts-requests.html',
})
export class AddonMessagesContactsRequestsPage implements OnInit, OnDestroy {
loaded = false;
canLoadMore = false;
loadMoreError = false;
requests: AddonMessagesConversationMember[] = [];
selectedUserId?: number;
protected memberInfoObserver: CoreEventObserver;
constructor() {
// Hide the "Would like to contact you" message when a contact request is confirmed.
this.memberInfoObserver = CoreEvents.on<AddonMessagesMemberInfoChangedEventData>(
AddonMessagesProvider.MEMBER_INFO_CHANGED_EVENT,
(data) => {
if (data.contactRequestConfirmed || data.contactRequestDeclined) {
const index = this.requests.findIndex((request) => request.id == data.userId);
if (index >= 0) {
this.requests.splice(index, 1);
}
}
},
CoreSites.instance.getCurrentSiteId(),
);
}
/**
* Component loaded.
*/
async ngOnInit(): Promise<void> {
try {
await this.fetchData();
if (this.requests.length) {
this.selectUser(this.requests[0].id, true);
}
} finally {
this.loaded = true;
}
// Workaround for infinite scrolling.
// @todo this.content.resize();
}
/**
* Fetch contact requests.
*
* @param refresh True if we are refreshing contact requests, false if we are loading more.
* @return Promise resolved when done.
*/
async fetchData(refresh: boolean = false): Promise<void> {
this.loadMoreError = false;
const limitFrom = refresh ? 0 : this.requests.length;
if (limitFrom === 0) {
// Always try to get latest data from server.
await AddonMessages.instance.invalidateContactRequestsCache();
}
try {
const result = await AddonMessages.instance.getContactRequests(limitFrom);
this.requests = refresh ? result.requests : this.requests.concat(result.requests);
this.canLoadMore = result.canLoadMore;
} catch (error) {
this.loadMoreError = true;
CoreDomUtils.instance.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingcontacts', true);
}
}
/**
* Refresh contact requests.
*
* @param refresher Refresher.
* @return Promise resolved when done.
*/
async refreshData(refresher?: CustomEvent<IonRefresher>): Promise<void> {
// Refresh the number of contacts requests to update badges.
AddonMessages.instance.refreshContactRequestsCount();
// No need to invalidate contact requests, we always try to get the latest.
await this.fetchData(true).finally(() => {
refresher?.detail.complete();
});
}
/**
* Load more contact requests.
*
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
* @return Resolved when done.
*/
async loadMore(infiniteComplete?: () => void): Promise<void> {
await this.fetchData().finally(() => {
infiniteComplete && infiniteComplete();
});
}
/**
* Notify that a contact has been selected.
*
* @param userId User id.
* @param onInit Whether the contact is selected on initial load.
*/
selectUser(userId: number, onInit: boolean = false): void {
this.selectedUserId = userId;
const data: AddonMessagesSplitViewLoadContactsEventData = {
userId,
onInit,
};
CoreEvents.trigger(AddonMessagesProvider.SPLIT_VIEW_LOAD_CONTACTS_EVENT, data);
// @todo: Check if split view is visible before
CoreNavigator.instance.navigateToSitePath('discussion', { params : { userId } });
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.memberInfoObserver?.off();
}
}

View File

@ -0,0 +1,19 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
</ion-buttons>
<ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title>
<ion-buttons slot="end">
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
</ion-button>
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu disappears in some cases. -->
<core-context-menu></core-context-menu>
</ion-buttons>
</ion-toolbar>
</ion-header>
<!-- @todo <core-split-view>-->
<ion-content>
<core-tabs [tabs]="tabs" hideUntil="true"></core-tabs>
</ion-content>

View File

@ -0,0 +1,64 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { Injector, NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { RouterModule, ROUTES, Routes } from '@angular/router';
import { CommonModule } from '@angular/common';
import { CoreSharedModule } from '@/core/shared.module';
import { ADDON_MESSAGES_CONTACTS_ROUTES } from './messages-contacts-routing.module';
import { AddonMessagesContactsPage } from './contacts.page';
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
import { resolveModuleRoutes } from '@/app/app-routing.module';
const routes: Routes = [
{
path: '',
component: AddonMessagesContactsPage,
},
];
function buildRoutes(injector: Injector): Routes {
const routes = resolveModuleRoutes(injector, ADDON_MESSAGES_CONTACTS_ROUTES);
return [
...buildTabMainRoutes(injector, {
path: '',
component: AddonMessagesContactsPage,
children: routes.children,
}),
...routes.siblings,
];
}
@NgModule({
imports: [
RouterModule.forChild(routes),
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreSharedModule,
],
providers: [
{ provide: ROUTES, multi: true, useFactory: buildRoutes, deps: [Injector] },
],
declarations: [
AddonMessagesContactsPage,
],
exports: [RouterModule],
})
export class AddonMessagesContactsPageModule {}

View File

@ -0,0 +1,134 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, OnDestroy, OnInit } from '@angular/core';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites';
import {
AddonMessages,
AddonMessagesContactRequestCountEventData,
AddonMessagesProvider,
AddonMessagesSplitViewLoadContactsEventData,
} from '../../services/messages';
import { CoreTab } from '@components/tabs/tabs';
import { CoreNavigator } from '@services/navigator';
// @todo import { CoreSplitViewComponent } from '@components/split-view/split-view';
/**
* Page that displays contacts and contact requests.
*/
@Component({
selector: 'page-addon-messages-contacts',
templateUrl: 'contacts.html',
})
export class AddonMessagesContactsPage implements OnInit, OnDestroy {
// @todo @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
protected contactsTab: CoreTab = {
id: 'contacts-confirmed',
class: '',
title: 'addon.messages.contacts',
icon: 'fas-address-book',
enabled: true,
page: 'main/messages/contacts/confirmed',
};
protected requestsTab: CoreTab = {
id: 'contact-requests',
class: '',
title: 'addon.messages.requests',
icon: 'fas-user-plus',
enabled: true,
page: 'main/messages/contacts/requests',
badge: '',
};
tabs: CoreTab[] = [];
protected siteId: string;
protected contactRequestsCountObserver: CoreEventObserver;
protected splitViewObserver: CoreEventObserver;
protected selectedUserId?: number; // User id of the conversation opened in the split view.
constructor() {
this.tabs = [this.contactsTab, this.requestsTab];
this.siteId = CoreSites.instance.getCurrentSiteId();
// Update the contact requests badge.
this.contactRequestsCountObserver = CoreEvents.on<AddonMessagesContactRequestCountEventData>(
AddonMessagesProvider.CONTACT_REQUESTS_COUNT_EVENT,
(data) => {
this.requestsTab.badge = data.count > 0 ? String(data.count) : '';
},
this.siteId,
);
// Update the contact requests badge.
this.splitViewObserver = CoreEvents.on<AddonMessagesSplitViewLoadContactsEventData>(
AddonMessagesProvider.SPLIT_VIEW_LOAD_CONTACTS_EVENT,
(data) => {
this.selectUser(data.userId, data.onInit);
},
this.siteId,
);
}
/**
* Page being initialized.
*/
ngOnInit(): void {
AddonMessages.instance.getContactRequestsCount(this.siteId); // Badge already updated by the observer.
}
/**
* Navigate to the search page.
*/
gotoSearch(): void {
CoreNavigator.instance.navigateToSitePath('search');
}
/**
* Set the selected user and open the conversation in the split view if needed.
*
* @param userId Id of the selected user, undefined to use the last selected user in the tab.
* @param onInit Whether the contact was selected on initial load.
*/
selectUser(userId: number, onInit = false): void {
/* @todo if (userId == this.selectedUserId && this.splitviewCtrl.isOn()) {
// No user conversation to open or it is already opened.
return;
}
if (onInit && !this.splitviewCtrl.isOn()) {
// Do not open a conversation by default when split view is not visible.
return;
}*/
this.selectedUserId = userId;
// @todo this.splitviewCtrl.push('AddonMessagesDiscussionPage', { userId });
CoreNavigator.instance.navigateToSitePath('discussion', { params : { userId } });
}
/**
* Page destroyed.
*/
ngOnDestroy(): void {
this.contactRequestsCountObserver?.off();
this.splitViewObserver?.off();
}
}

View File

@ -0,0 +1,33 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
import { ModuleRoutesConfig } from '@/app/app-routing.module';
export const ADDON_MESSAGES_CONTACTS_ROUTES = new InjectionToken('ADDON_MESSAGES_CONTACTS_ROUTES');
@NgModule()
export class AddonMessagesContactsRoutingModule {
static forChild(routes: ModuleRoutesConfig): ModuleWithProviders<AddonMessagesContactsRoutingModule> {
return {
ngModule: AddonMessagesContactsRoutingModule,
providers: [
{ provide: ADDON_MESSAGES_CONTACTS_ROUTES, multi: true, useValue: routes },
],
};
}
}

View File

@ -43,6 +43,7 @@ export class AddonMessagesProvider {
static readonly READ_CHANGED_EVENT = 'addon_messages_read_changed_event';
static readonly OPEN_CONVERSATION_EVENT = 'addon_messages_open_conversation_event'; // Notify a conversation should be opened.
static readonly SPLIT_VIEW_LOAD_INDEX_EVENT = 'addon_messages_split_view_load_index_event'; // Used on 3.5 or lower.
static readonly SPLIT_VIEW_LOAD_CONTACTS_EVENT = 'addon_messages_split_view_load_contacts_event'; // Used on 3.6 or greater.
static readonly UPDATE_CONVERSATION_LIST_EVENT = 'addon_messages_update_conversation_list_event';
static readonly MEMBER_INFO_CHANGED_EVENT = 'addon_messages_member_changed_event';
static readonly UNREAD_CONVERSATION_COUNTS_EVENT = 'addon_messages_unread_conversation_counts_event';
@ -3639,3 +3640,11 @@ export type AddonMessagesSplitViewLoadIndexEventData = {
onlyWithSplitView?: boolean;
message?: number;
};
/**
* Data sent by SPLIT_VIEW_LOAD_CONTACTS_EVENT event. Used on 3.6 or greater.
*/
export type AddonMessagesSplitViewLoadContactsEventData = {
userId: number;
onInit: boolean;
};