MOBILE-3631 messages: Add group info modal
parent
e3b28d87e5
commit
210518d549
|
@ -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 {}
|
|
@ -0,0 +1,54 @@
|
|||
<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.groupinfo' | translate }}</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||
<ion-icon name="close" slot="icon-only"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<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">
|
||||
<ion-item class="ion-text-center" *ngIf="conversation">
|
||||
<ion-label>
|
||||
<div class="large-avatar">
|
||||
<img class="avatar" [src]="conversation!.imageurl" core-external-content [alt]="conversation!.name"
|
||||
role="presentation" onError="this.src='assets/img/group-avatar.png'">
|
||||
</div>
|
||||
<h2>
|
||||
<core-format-text [text]="conversation!.name" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
||||
</h2>
|
||||
<p>
|
||||
<core-format-text *ngIf="conversation!.subname" [text]="conversation!.subname" contextLevel="system"
|
||||
[contextInstanceId]="0">
|
||||
</core-format-text>
|
||||
</p>
|
||||
<p>{{ 'addon.messages.numparticipants' | translate:{$a: conversation!.membercount} }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let member of members"
|
||||
(click)="closeModal(member.id)" detail>
|
||||
<core-user-avatar [user]="member" [linkProfile]="false" [checkOnline]="member.showonlinestatus" slot="start">
|
||||
</core-user-avatar>
|
||||
<ion-label>
|
||||
<h2>
|
||||
{{ member.fullname }}
|
||||
<ion-icon name="fas-user-slash" *ngIf="member.isblocked" [title]="'addon.messages.contactblocked' | translate">
|
||||
</ion-icon>
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreMembers($event)" [error]="loadMoreError">
|
||||
</core-infinite-loading>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -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<void> {
|
||||
// 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<void> {
|
||||
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<void> {
|
||||
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<IonRefresher>): Promise<void> {
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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<AddonMessagesOpenConversationEventData>(
|
||||
AddonMessagesProvider.OPEN_CONVERSATION_EVENT,
|
||||
{ userId: result.data.userId },
|
||||
{ userId: result.data },
|
||||
this.siteId,
|
||||
);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue