From 210518d549dd017f7e278630f978f5a44cacd3ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 26 Jan 2021 16:15:17 +0100 Subject: [PATCH] MOBILE-3631 messages: Add group info modal --- .../messages/components/components.module.ts | 39 +++++ .../conversation-info/conversation-info.html | 54 +++++++ .../conversation-info/conversation-info.ts | 146 ++++++++++++++++++ .../pages/discussion/discussion.module.ts | 2 + .../pages/discussion/discussion.page.ts | 16 +- 5 files changed, 249 insertions(+), 8 deletions(-) create mode 100644 src/addons/messages/components/components.module.ts create mode 100644 src/addons/messages/components/conversation-info/conversation-info.html create mode 100644 src/addons/messages/components/conversation-info/conversation-info.ts diff --git a/src/addons/messages/components/components.module.ts b/src/addons/messages/components/components.module.ts new file mode 100644 index 000000000..ec68cc07b --- /dev/null +++ b/src/addons/messages/components/components.module.ts @@ -0,0 +1,39 @@ +// (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 { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreSharedModule } from '@/core/shared.module'; + +import { AddonMessagesConversationInfoComponent } from './conversation-info/conversation-info'; + + +@NgModule({ + declarations: [ + AddonMessagesConversationInfoComponent, + ], + imports: [ + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreSharedModule, + ], + entryComponents: [ + AddonMessagesConversationInfoComponent, + ], +}) +export class AddonMessagesComponentsModule {} diff --git a/src/addons/messages/components/conversation-info/conversation-info.html b/src/addons/messages/components/conversation-info/conversation-info.html new file mode 100644 index 000000000..a07fe4cd0 --- /dev/null +++ b/src/addons/messages/components/conversation-info/conversation-info.html @@ -0,0 +1,54 @@ + + + + + + {{ 'addon.messages.groupinfo' | translate }} + + + + + + + + + + + + + + + +
+ +
+

+ +

+

+ + +

+

{{ 'addon.messages.numparticipants' | translate:{$a: conversation!.membercount} }}

+
+
+ + + + + +

+ {{ member.fullname }} + + +

+
+
+ + + +
+
diff --git a/src/addons/messages/components/conversation-info/conversation-info.ts b/src/addons/messages/components/conversation-info/conversation-info.ts new file mode 100644 index 000000000..80641149d --- /dev/null +++ b/src/addons/messages/components/conversation-info/conversation-info.ts @@ -0,0 +1,146 @@ +// (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, OnInit } from '@angular/core'; +import { IonRefresher } from '@ionic/angular'; +import { + AddonMessagesConversationFormatted, + AddonMessagesConversationMember, + AddonMessages, +} from '../../services/messages'; +import { CoreDomUtils } from '@services/utils/dom'; +import { ActivatedRoute } from '@angular/router'; +import { ModalController } from '@singletons'; + +/** + * Component that displays the list of conversations, including group conversations. + */ +@Component({ + selector: 'page-addon-messages-conversation-info', + templateUrl: 'conversation-info.html', +}) +export class AddonMessagesConversationInfoComponent implements OnInit { + + loaded = false; + conversation?: AddonMessagesConversationFormatted; + members: AddonMessagesConversationMember[] = []; + canLoadMore = false; + loadMoreError = false; + + protected conversationId!: number; + + constructor( + protected route: ActivatedRoute, + ) { + } + + /** + * Component loaded. + */ + ngOnInit(): void { + this.route.queryParams.subscribe(async params => { + this.conversationId = parseInt(params['conversationId'], 10); + + this.loaded = false; + this.fetchData().finally(() => { + this.loaded = true; + }); + }); + } + + /** + * Fetch the required data. + * + * @return Promise resolved when done. + */ + protected async fetchData(): Promise { + // Get the conversation data first. + try { + const conversation = await AddonMessages.instance.getConversation(this.conversationId, false, true, 0, 0); + this.conversation = conversation; + + // Now get the members. + await this.fetchMembers(); + } catch (error) { + CoreDomUtils.instance.showErrorModalDefault(error, 'Error getting members.'); + } + } + + /** + * Get conversation members. + * + * @param loadingMore Whether we are loading more data or just the first ones. + * @return Promise resolved when done. + */ + protected async fetchMembers(loadingMore?: boolean): Promise { + this.loadMoreError = false; + + const limitFrom = loadingMore ? this.members.length : 0; + + const data = await AddonMessages.instance.getConversationMembers(this.conversationId, limitFrom); + if (loadingMore) { + this.members = this.members.concat(data.members); + } else { + this.members = data.members; + } + + this.canLoadMore = data.canLoadMore; + } + + /** + * Function to load more members. + * + * @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading. + * @return Resolved when done. + */ + async loadMoreMembers(infiniteComplete?: () => void): Promise { + try { + await this.fetchMembers(true); + } catch (error) { + CoreDomUtils.instance.showErrorModalDefault(error, 'Error getting members.'); + this.loadMoreError = true; + } finally { + infiniteComplete && infiniteComplete(); + } + } + + /** + * Refresh the data. + * + * @param refresher Refresher. + * @return Promise resolved when done. + */ + async refreshData(refresher?: CustomEvent): Promise { + const promises: Promise[] = []; + + promises.push(AddonMessages.instance.invalidateConversation(this.conversationId)); + promises.push(AddonMessages.instance.invalidateConversationMembers(this.conversationId)); + + await Promise.all(promises); + + await this.fetchData().finally(() => { + refresher?.detail.complete(); + }); + } + + /** + * Close modal. + * + * @param userId User conversation to load. + */ + closeModal(userId?: number): void { + ModalController.instance.dismiss(userId); + } + +} diff --git a/src/addons/messages/pages/discussion/discussion.module.ts b/src/addons/messages/pages/discussion/discussion.module.ts index 4d19beffd..5147cdb35 100644 --- a/src/addons/messages/pages/discussion/discussion.module.ts +++ b/src/addons/messages/pages/discussion/discussion.module.ts @@ -21,6 +21,7 @@ import { CommonModule } from '@angular/common'; import { CoreSharedModule } from '@/core/shared.module'; import { AddonMessagesDiscussionPage } from './discussion.page'; +import { AddonMessagesComponentsModule } from '@addons/messages/components/components.module'; const routes: Routes = [ { @@ -36,6 +37,7 @@ const routes: Routes = [ IonicModule, TranslateModule.forChild(), CoreSharedModule, + AddonMessagesComponentsModule, ], declarations: [ AddonMessagesDiscussionPage, diff --git a/src/addons/messages/pages/discussion/discussion.page.ts b/src/addons/messages/pages/discussion/discussion.page.ts index c0b2b667d..c9b3d1ba2 100644 --- a/src/addons/messages/pages/discussion/discussion.page.ts +++ b/src/addons/messages/pages/discussion/discussion.page.ts @@ -52,6 +52,7 @@ import { ActivatedRoute } from '@angular/router'; import { AddonMessagesOfflineMessagesDBRecordFormatted, } from '@addons/messages/services/database/messages'; +import { AddonMessagesConversationInfoComponent } from '../../components/conversation-info/conversation-info'; /** * Page that displays a message discussion page. @@ -171,8 +172,8 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView this.showInfo = !backViewPage || !CoreTextUtils.instance.matchesGlob(backViewPage, '**/user/profile'); this.loaded = false; - this.conversationId = parseInt(params['conversationId'], 10) || undefined; - this.userId = parseInt(params['userId'], 10) || undefined; + this.conversationId = params['conversationId'] ? parseInt(params['conversationId'], 10) : undefined; + this.userId = params['userId'] ? parseInt(params['userId'], 10) : undefined; this.showKeyboard = !!params['showKeyboard']; await this.fetchData(); @@ -289,7 +290,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView // Get the member info. Invalidate first to make sure we get the latest status. promises.push(AddonMessages.instance.invalidateMemberInfo(this.userId).then(() => AddonMessages.instance.getMemberInfo(this.userId!)).then((member) => { - this.otherMember = member; if (!exists && member) { this.conversationImage = member.profileimageurl; this.title = member.fullname; @@ -362,10 +362,10 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView if (this.messagesBeingSent > 0) { // We do not poll while a message is being sent or we could confuse the user. // Otherwise, his message would disappear from the list, and he'd have to wait for the interval to check for messages. - throw null; + return; } else if (this.fetching) { // Already fetching. - throw null; + return; } else if (this.groupMessagingEnabled && !this.conversationId) { // Don't have enough data to fetch messages. throw new CoreError('No enough data provided to fetch messages'); @@ -1286,7 +1286,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView if (this.isGroup) { // Display the group information. const modal = await ModalController.instance.create({ - component: 'AddonMessagesConversationInfoPage', // @todo + component: AddonMessagesConversationInfoComponent, componentProps: { conversationId: this.conversationId, }, @@ -1296,7 +1296,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView const result = await modal.onDidDismiss(); - if (typeof result.data.userId != 'undefined') { + if (typeof result.data != 'undefined') { const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/**/discussion'); // Open user conversation. @@ -1304,7 +1304,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView // Notify the left pane to load it, this way the right conversation will be highlighted. CoreEvents.trigger( AddonMessagesProvider.OPEN_CONVERSATION_EVENT, - { userId: result.data.userId }, + { userId: result.data }, this.siteId, ); } else {