openvidu-components: Allowed external panels

- Allowed injecting external panels and exported the panel service for toggling panels and subscribe to the panel status
- Renamed menu to panel
- Updated docs
pull/713/head
csantosm 2022-04-06 12:00:42 +02:00
parent 150657763c
commit d7b81739e7
16 changed files with 236 additions and 101 deletions

View File

@ -10,7 +10,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ChatMessage } from '../../../models/chat.model'; import { ChatMessage } from '../../../models/chat.model';
import { MenuType } from '../../../models/menu.model'; import { PanelType } from '../../../models/panel.model';
import { ChatService } from '../../../services/chat/chat.service'; import { ChatService } from '../../../services/chat/chat.service';
import { PanelService } from '../../../services/panel/panel.service'; import { PanelService } from '../../../services/panel/panel.service';
@ -65,14 +65,14 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
/** /**
* @ignore * @ignore
*/ */
constructor(private chatService: ChatService, private PanelService: PanelService, private cd: ChangeDetectorRef) {} constructor(private chatService: ChatService, private panelService: PanelService, private cd: ChangeDetectorRef) {}
/** /**
* @ignore * @ignore
*/ */
@HostListener('document:keydown.escape', ['$event']) @HostListener('document:keydown.escape', ['$event'])
onKeydownHandler(event: KeyboardEvent) { onKeydownHandler(event: KeyboardEvent) {
if (this.PanelService.isPanelOpened()) { if (this.panelService.isPanelOpened()) {
this.close(); this.close();
} }
} }
@ -119,13 +119,13 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
} }
close() { close() {
this.PanelService.togglePanel(MenuType.CHAT); this.panelService.togglePanel(PanelType.CHAT);
} }
private subscribeToMessages() { private subscribeToMessages() {
this.chatMessageSubscription = this.chatService.messagesObs.subscribe((messages: ChatMessage[]) => { this.chatMessageSubscription = this.chatService.messagesObs.subscribe((messages: ChatMessage[]) => {
this.messageList = messages; this.messageList = messages;
if (this.PanelService.isPanelOpened()) { if (this.panelService.isPanelOpened()) {
this.scrollToBottom(); this.scrollToBottom();
this.cd.markForCheck(); this.cd.markForCheck();
} }

View File

@ -9,4 +9,9 @@
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container> <ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container>
</ng-container> </ng-container>
<!-- External additional panels -->
<ng-container *ngIf="additionalPanelsTemplate && isExternalPanelOpened">
<ng-container *ngTemplateOutlet="additionalPanelsTemplate"></ng-container>
</ng-container>

View File

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core';
import { skip, Subscription } from 'rxjs'; import { skip, Subscription } from 'rxjs';
import { ChatPanelDirective, ParticipantsPanelDirective } from '../../directives/template/openvidu-angular.directive'; import { ChatPanelDirective, AdditionalPanelsDirective, ParticipantsPanelDirective } from '../../directives/template/openvidu-angular.directive';
import { MenuType } from '../../models/menu.model'; import { PanelType } from '../../models/panel.model';
import { PanelService } from '../../services/panel/panel.service'; import { PanelService } from '../../services/panel/panel.service';
/** /**
@ -32,6 +32,7 @@ import { PanelService } from '../../services/panel/panel.service';
* |:----------------------------------:|:---------------------------------------------:| * |:----------------------------------:|:---------------------------------------------:|
* | ***ovChatPanel** | {@link ChatPanelDirective} | * | ***ovChatPanel** | {@link ChatPanelDirective} |
* | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} | * | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} |
* | ***ovAdditionalPanels** | {@link AdditionalPanelsDirective} |
* *
* <p class="component-link-text"> * <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span> * <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
@ -57,6 +58,11 @@ export class PanelComponent implements OnInit {
*/ */
@ContentChild('chatPanel', { read: TemplateRef }) chatPanelTemplate: TemplateRef<any>; @ContentChild('chatPanel', { read: TemplateRef }) chatPanelTemplate: TemplateRef<any>;
/**
* @ignore
*/
@ContentChild('additionalPanels', { read: TemplateRef }) additionalPanelsTemplate: TemplateRef<any>;
@ContentChild(ParticipantsPanelDirective) @ContentChild(ParticipantsPanelDirective)
set externalParticipantPanel(externalParticipantsPanel: ParticipantsPanelDirective) { set externalParticipantPanel(externalParticipantsPanel: ParticipantsPanelDirective) {
// This directive will has value only when PARTICIPANTS PANEL component tagged with '*ovParticipantsPanel' // This directive will has value only when PARTICIPANTS PANEL component tagged with '*ovParticipantsPanel'
@ -75,9 +81,23 @@ export class PanelComponent implements OnInit {
} }
} }
@ContentChild(AdditionalPanelsDirective)
set externalAdditionalPanels(externalAdditionalPanels: AdditionalPanelsDirective) {
// This directive will has value only when ADDITIONAL PANELS component tagged with '*ovPanelAdditionalPanels'
// is inside of the PANEL component tagged with '*ovPanel'
if (externalAdditionalPanels) {
this.additionalPanelsTemplate = externalAdditionalPanels.template;
}
}
isParticipantsPanelOpened: boolean; isParticipantsPanelOpened: boolean;
isChatPanelOpened: boolean; isChatPanelOpened: boolean;
private menuSubscription: Subscription;
/**
* @internal
*/
isExternalPanelOpened: boolean;
private panelSubscription: Subscription;
/** /**
* @ignore * @ignore
@ -91,13 +111,14 @@ export class PanelComponent implements OnInit {
ngOnDestroy() { ngOnDestroy() {
this.isChatPanelOpened = false; this.isChatPanelOpened = false;
this.isParticipantsPanelOpened = false; this.isParticipantsPanelOpened = false;
if (this.menuSubscription) this.menuSubscription.unsubscribe(); if (this.panelSubscription) this.panelSubscription.unsubscribe();
} }
private subscribeToPanelToggling() { private subscribeToPanelToggling() {
this.menuSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: MenuType }) => { this.panelSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: PanelType | string }) => {
this.isChatPanelOpened = ev.opened && ev.type === MenuType.CHAT; this.isChatPanelOpened = ev.opened && ev.type === PanelType.CHAT;
this.isParticipantsPanelOpened = ev.opened && ev.type === MenuType.PARTICIPANTS; this.isParticipantsPanelOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
this.isExternalPanelOpened = ev.opened && ev.type !== PanelType.PARTICIPANTS && ev.type !== PanelType.CHAT;
this.cd.markForCheck(); this.cd.markForCheck();
}); });
} }

View File

@ -19,6 +19,9 @@
<ng-container *ngTemplateOutlet="participantPanelItemTemplate; context: { $implicit: participant }"></ng-container> <ng-container *ngTemplateOutlet="participantPanelItemTemplate; context: { $implicit: participant }"></ng-container>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<ng-template #defaultParticipantPanelItem let-participant>
<ov-participant-panel-item [participant]="participant" id="default-participant-panel-item"></ov-participant-panel-item>
</ng-template>

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ParticipantAbstractModel } from '../../../../models/participant.model'; import { ParticipantAbstractModel } from '../../../../models/participant.model';
import { ParticipantService } from '../../../../services/participant/participant.service'; import { ParticipantService } from '../../../../services/participant/participant.service';
import { PanelService } from '../../../..//services/panel/panel.service'; import { PanelService } from '../../../..//services/panel/panel.service';
@ -44,10 +44,15 @@ import { Subscription } from 'rxjs';
styleUrls: ['./participants-panel.component.css'], styleUrls: ['./participants-panel.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ParticipantsPanelComponent implements OnInit, OnDestroy { export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewInit {
localParticipant: any; localParticipant: any;
remoteParticipants: ParticipantAbstractModel[] = []; remoteParticipants: ParticipantAbstractModel[] = [];
/**
* @ignore
*/
@ViewChild('defaultParticipantPanelItem', { static: false, read: TemplateRef }) defaultParticipantPanelItemTemplate: TemplateRef<any>;
/** /**
* @ignore * @ignore
*/ */
@ -70,7 +75,7 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy {
*/ */
constructor( constructor(
protected participantService: ParticipantService, protected participantService: ParticipantService,
protected PanelService: PanelService, protected panelService: PanelService,
private cd: ChangeDetectorRef private cd: ChangeDetectorRef
) {} ) {}
@ -99,7 +104,16 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy {
if (this.remoteParticipantsSubs) this.remoteParticipantsSubs.unsubscribe; if (this.remoteParticipantsSubs) this.remoteParticipantsSubs.unsubscribe;
} }
ngAfterViewInit(){
if(!this.participantPanelItemTemplate) {
// the user has override the default participants panel but not the 'participant-panel-item'
// so the default component must be injected
this.participantPanelItemTemplate = this.defaultParticipantPanelItemTemplate
this.cd.markForCheck();
}
}
close() { close() {
this.PanelService.closeMenu(); this.panelService.closePanel();
} }
} }

View File

@ -24,6 +24,10 @@
z-index: 1; z-index: 1;
} }
.mat-drawer.mat-drawer-side {
z-index: 1;
}
.sidenav-main { .sidenav-main {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;

View File

@ -25,7 +25,7 @@ import { MatSidenav } from '@angular/material/sidenav';
import { SidenavMode } from '../../models/layout.model'; import { SidenavMode } from '../../models/layout.model';
import { LayoutService } from '../../services/layout/layout.service'; import { LayoutService } from '../../services/layout/layout.service';
import { Subscription, skip } from 'rxjs'; import { Subscription, skip } from 'rxjs';
import { MenuType } from '../../models/menu.model'; import { PanelType } from '../../models/panel.model';
import { PanelService } from '../../services/panel/panel.service'; import { PanelService } from '../../services/panel/panel.service';
import { PlatformService } from '../../services/platform/platform.service'; import { PlatformService } from '../../services/platform/platform.service';
@ -45,8 +45,6 @@ export class SessionComponent implements OnInit {
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>; @ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
@Output() onSessionCreated = new EventEmitter<any>(); @Output() onSessionCreated = new EventEmitter<any>();
// @Output() _publisher = new EventEmitter<any>();
// @Output() _error = new EventEmitter<any>();
session: Session; session: Session;
sessionScreen: Session; sessionScreen: Session;
@ -54,8 +52,6 @@ export class SessionComponent implements OnInit {
sideMenu: MatSidenav; sideMenu: MatSidenav;
sidenavMode: SidenavMode = SidenavMode.SIDE; sidenavMode: SidenavMode = SidenavMode.SIDE;
isParticipantsPanelOpened: boolean;
isChatPanelOpened: boolean;
protected readonly SIDENAV_WIDTH_LIMIT_MODE = 790; protected readonly SIDENAV_WIDTH_LIMIT_MODE = 790;
protected menuSubscription: Subscription; protected menuSubscription: Subscription;
@ -73,8 +69,7 @@ export class SessionComponent implements OnInit {
protected chatService: ChatService, protected chatService: ChatService,
protected tokenService: TokenService, protected tokenService: TokenService,
protected layoutService: LayoutService, protected layoutService: LayoutService,
protected panelService: PanelService, protected panelService: PanelService
private platformService: PlatformService
) { ) {
this.log = this.loggerSrv.get('SessionComponent'); this.log = this.loggerSrv.get('SessionComponent');
} }
@ -126,8 +121,6 @@ export class SessionComponent implements OnInit {
this.participantService.clear(); this.participantService.clear();
this.session = null; this.session = null;
this.sessionScreen = null; this.sessionScreen = null;
this.isChatPanelOpened = false;
this.isParticipantsPanelOpened = false;
if (this.menuSubscription) this.menuSubscription.unsubscribe(); if (this.menuSubscription) this.menuSubscription.unsubscribe();
if (this.layoutWidthSubscription) this.layoutWidthSubscription.unsubscribe(); if (this.layoutWidthSubscription) this.layoutWidthSubscription.unsubscribe();
} }
@ -153,10 +146,8 @@ export class SessionComponent implements OnInit {
this.updateLayoutInterval = setInterval(() => this.layoutService.update(), 50); this.updateLayoutInterval = setInterval(() => this.layoutService.update(), 50);
}); });
this.menuSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: MenuType }) => { this.menuSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean, type?: PanelType }) => {
if (this.sideMenu) { if (this.sideMenu) {
this.isChatPanelOpened = ev.opened && ev.type === MenuType.CHAT;
this.isParticipantsPanelOpened = ev.opened && ev.type === MenuType.PARTICIPANTS;
ev.opened ? this.sideMenu.open() : this.sideMenu.close(); ev.opened ? this.sideMenu.open() : this.sideMenu.close();
} }
}); });

View File

@ -72,7 +72,7 @@
mat-icon-button mat-icon-button
id="participants-panel-btn" id="participants-panel-btn"
*ngIf="!isMinimal && showParticipantsPanelButton" *ngIf="!isMinimal && showParticipantsPanelButton"
matTooltip="Show articipants" matTooltip="Participants"
(click)="toggleParticipantsPanel()" (click)="toggleParticipantsPanel()"
[disabled]="isConnectionLost" [disabled]="isConnectionLost"
[class.active-btn]="isParticipantsOpened" [class.active-btn]="isParticipantsOpened"
@ -85,6 +85,7 @@
mat-icon-button mat-icon-button
id="chat-panel-btn" id="chat-panel-btn"
*ngIf="!isMinimal && showChatPanelButton" *ngIf="!isMinimal && showChatPanelButton"
matTooltip="Chat"
(click)="toggleChatPanel()" (click)="toggleChatPanel()"
[disabled]="isConnectionLost" [disabled]="isConnectionLost"
[class.active-btn]="isChatOpened" [class.active-btn]="isChatOpened"
@ -99,5 +100,10 @@
chat chat
</mat-icon> </mat-icon>
</button> </button>
<!-- External additional panel buttons -->
<ng-container *ngIf="toolbarAdditionalPanelButtonsTemplate">
<ng-container *ngTemplateOutlet="toolbarAdditionalPanelButtonsTemplate"></ng-container>
</ng-container>
</div> </div>
</mat-toolbar> </mat-toolbar>

View File

@ -24,9 +24,9 @@ import { ActionService } from '../../services/action/action.service';
import { DeviceService } from '../../services/device/device.service'; import { DeviceService } from '../../services/device/device.service';
import { ChatMessage } from '../../models/chat.model'; import { ChatMessage } from '../../models/chat.model';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
import { MenuType } from '../../models/menu.model'; import { PanelType } from '../../models/panel.model';
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service'; import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
import { ToolbarAdditionalButtonsDirective } from '../../directives/template/openvidu-angular.directive'; import { ToolbarAdditionalButtonsDirective, ToolbarAdditionalPanelButtonsDirective } from '../../directives/template/openvidu-angular.directive';
import { ParticipantAbstractModel } from '../../models/participant.model'; import { ParticipantAbstractModel } from '../../models/participant.model';
/** /**
@ -75,6 +75,7 @@ import { ParticipantAbstractModel } from '../../models/participant.model';
* | **Directive** | **Reference** | * | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:| * |:----------------------------------:|:---------------------------------------------:|
* | ***ovToolbarAdditionalButtons** | {@link ToolbarAdditionalButtonsDirective} | * | ***ovToolbarAdditionalButtons** | {@link ToolbarAdditionalButtonsDirective} |
* |***ovToolbarAdditionalPanelButtons** | {@link ToolbarAdditionalPanelButtonsDirective} |
* *
* <p class="component-link-text"> * <p class="component-link-text">
* <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span> * <span class="italic">See all {@link OpenViduAngularDirectiveModule OpenVidu Angular Directives}</span>
@ -95,6 +96,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
*/ */
@ContentChild('toolbarAdditionalButtons', { read: TemplateRef }) toolbarAdditionalButtonsTemplate: TemplateRef<any>; @ContentChild('toolbarAdditionalButtons', { read: TemplateRef }) toolbarAdditionalButtonsTemplate: TemplateRef<any>;
/**
* @ignore
*/
@ContentChild('toolbarAdditionalPanelButtons', { read: TemplateRef }) toolbarAdditionalPanelButtonsTemplate: TemplateRef<any>;
/** /**
* @ignore * @ignore
*/ */
@ -107,6 +113,18 @@ export class ToolbarComponent implements OnInit, OnDestroy {
} }
} }
/**
* @ignore
*/
@ContentChild(ToolbarAdditionalPanelButtonsDirective)
set externalAdditionalPanelButtons(externalAdditionalPanelButtons: ToolbarAdditionalPanelButtonsDirective) {
// This directive will has value only when ADDITIONAL PANEL BUTTONS component tagget with '*ovToolbarAdditionalPanelButtons' directive
// is inside of the TOOLBAR component tagged with '*ovToolbar' directive
if (externalAdditionalPanelButtons) {
this.toolbarAdditionalPanelButtonsTemplate = externalAdditionalPanelButtons.template;
}
}
@Output() onLeaveButtonClicked = new EventEmitter<any>(); @Output() onLeaveButtonClicked = new EventEmitter<any>();
@Output() onCameraButtonClicked = new EventEmitter<any>(); @Output() onCameraButtonClicked = new EventEmitter<any>();
@Output() onMicrophoneButtonClicked = new EventEmitter<any>(); @Output() onMicrophoneButtonClicked = new EventEmitter<any>();
@ -199,7 +217,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
private log: ILogger; private log: ILogger;
private minimalSub: Subscription; private minimalSub: Subscription;
private menuTogglingSubscription: Subscription; private panelTogglingSubscription: Subscription;
private chatMessagesSubscription: Subscription; private chatMessagesSubscription: Subscription;
private localParticipantSubscription: Subscription; private localParticipantSubscription: Subscription;
private screenshareButtonSub: Subscription; private screenshareButtonSub: Subscription;
@ -269,7 +287,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
} }
ngOnDestroy(): void { ngOnDestroy(): void {
if (this.menuTogglingSubscription) this.menuTogglingSubscription.unsubscribe(); if (this.panelTogglingSubscription) this.panelTogglingSubscription.unsubscribe();
if (this.chatMessagesSubscription) this.chatMessagesSubscription.unsubscribe(); if (this.chatMessagesSubscription) this.chatMessagesSubscription.unsubscribe();
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe(); if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe(); if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe();
@ -340,7 +358,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
*/ */
toggleParticipantsPanel() { toggleParticipantsPanel() {
this.onParticipantsPanelButtonClicked.emit(); this.onParticipantsPanelButtonClicked.emit();
this.panelService.togglePanel(MenuType.PARTICIPANTS); this.panelService.togglePanel(PanelType.PARTICIPANTS);
} }
/** /**
@ -348,7 +366,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
*/ */
toggleChatPanel() { toggleChatPanel() {
this.onChatPanelButtonClicked.emit(); this.onChatPanelButtonClicked.emit();
this.panelService.togglePanel(MenuType.CHAT); this.panelService.togglePanel(PanelType.CHAT);
} }
/** /**
@ -363,7 +381,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
protected subscribeToReconnection() { protected subscribeToReconnection() {
this.session.on('reconnecting', () => { this.session.on('reconnecting', () => {
if (this.panelService.isPanelOpened()) { if (this.panelService.isPanelOpened()) {
this.panelService.closeMenu(); this.panelService.closePanel();
} }
this.isConnectionLost = true; this.isConnectionLost = true;
}); });
@ -372,9 +390,9 @@ export class ToolbarComponent implements OnInit, OnDestroy {
}); });
} }
protected subscribeToMenuToggling() { protected subscribeToMenuToggling() {
this.menuTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: MenuType }) => { this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: PanelType }) => {
this.isChatOpened = ev.opened && ev.type === MenuType.CHAT; this.isChatOpened = ev.opened && ev.type === PanelType.CHAT;
this.isParticipantsOpened = ev.opened && ev.type === MenuType.PARTICIPANTS; this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
if (this.isChatOpened) { if (this.isChatOpened) {
this.unreadMessages = 0; this.unreadMessages = 0;
} }

View File

@ -51,6 +51,10 @@
<ng-template #toolbarAdditionalButtons> <ng-template #toolbarAdditionalButtons>
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container> <ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container>
</ng-template> </ng-template>
<ng-template #toolbarAdditionalPanelButtons>
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalPanelButtonsTemplate"></ng-container>
</ng-template>
</ov-toolbar> </ov-toolbar>
</ng-template> </ng-template>
@ -63,6 +67,10 @@
<ng-template #participantsPanel> <ng-template #participantsPanel>
<ng-container *ngTemplateOutlet="openviduAngularParticipantsPanelTemplate"></ng-container> <ng-container *ngTemplateOutlet="openviduAngularParticipantsPanelTemplate"></ng-container>
</ng-template> </ng-template>
<ng-template #additionalPanels>
<ng-container *ngTemplateOutlet="openviduAngularAdditionalPanelsTemplate"></ng-container>
</ng-template>
</ov-panel> </ov-panel>
</ng-template> </ng-template>

View File

@ -15,12 +15,14 @@ import { Subscription } from 'rxjs';
import { import {
ChatPanelDirective, ChatPanelDirective,
LayoutDirective, LayoutDirective,
AdditionalPanelsDirective,
PanelDirective, PanelDirective,
ParticipantPanelItemDirective, ParticipantPanelItemDirective,
ParticipantPanelItemElementsDirective, ParticipantPanelItemElementsDirective,
ParticipantsPanelDirective, ParticipantsPanelDirective,
StreamDirective, StreamDirective,
ToolbarAdditionalButtonsDirective, ToolbarAdditionalButtonsDirective,
ToolbarAdditionalPanelButtonsDirective,
ToolbarDirective ToolbarDirective
} from '../../directives/template/openvidu-angular.directive'; } from '../../directives/template/openvidu-angular.directive';
import { ILogger } from '../../models/logger.model'; import { ILogger } from '../../models/logger.model';
@ -79,11 +81,13 @@ import { TokenService } from '../../services/token/token.service';
* It will recognise the following {@link https://angular.io/guide/structural-directives Angular structural directives} * It will recognise the following {@link https://angular.io/guide/structural-directives Angular structural directives}
* in the elements added as children. * in the elements added as children.
* *
* | **Directive** | **Reference** | * | **Directive** | **Reference** |
* |:----------------------------------:|:---------------------------------------------:| * |:-----------------------------------:|:---------------------------------------------:|
* | ***ovToolbar** | {@link ToolbarDirective} | * | ***ovToolbar** | {@link ToolbarDirective} |
* | ***ovToolbarAdditionalButtons** | {@link ToolbarAdditionalButtonsDirective} | * | ***ovToolbarAdditionalButtons** | {@link ToolbarAdditionalButtonsDirective} |
* |***ovToolbarAdditionalPanelButtons** | {@link ToolbarAdditionalPanelButtonsDirective} |
* | ***ovPanel** | {@link PanelDirective} | * | ***ovPanel** | {@link PanelDirective} |
* | ***ovAdditionalPanels** | {@link AdditionalPanelsDirective} |
* | ***ovChatPanel** | {@link ChatPanelDirective} | * | ***ovChatPanel** | {@link ChatPanelDirective} |
* | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} | * | ***ovParticipantsPanel** | {@link ParticipantsPanelDirective} |
* | ***ovParticipantPanelItem** | {@link ParticipantPanelItemDirective} | * | ***ovParticipantPanelItem** | {@link ParticipantPanelItemDirective} |
@ -112,6 +116,14 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
* @internal * @internal
*/ */
@ContentChild(ToolbarAdditionalButtonsDirective) externalToolbarAdditionalButtons: ToolbarAdditionalButtonsDirective; @ContentChild(ToolbarAdditionalButtonsDirective) externalToolbarAdditionalButtons: ToolbarAdditionalButtonsDirective;
/**
* @internal
*/
@ContentChild(ToolbarAdditionalPanelButtonsDirective) externalToolbarAdditionalPanelButtons: ToolbarAdditionalPanelButtonsDirective;
/**
* @internal
*/
@ContentChild(AdditionalPanelsDirective) externalAdditionalPanels: AdditionalPanelsDirective;
// *** Panels *** // *** Panels ***
@ -183,6 +195,10 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
* @internal * @internal
*/ */
openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>; openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularToolbarAdditionalPanelButtonsTemplate: TemplateRef<any>;
/** /**
* @internal * @internal
*/ */
@ -195,6 +211,10 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
* @internal * @internal
*/ */
openviduAngularParticipantsPanelTemplate: TemplateRef<any>; openviduAngularParticipantsPanelTemplate: TemplateRef<any>;
/**
* @internal
*/
openviduAngularAdditionalPanelsTemplate: TemplateRef<any>;
/** /**
* @internal * @internal
*/ */
@ -346,20 +366,24 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
*/ */
ngAfterViewInit() { ngAfterViewInit() {
if (this.externalToolbar) { if (this.externalToolbar) {
this.openviduAngularToolbarTemplate = this.externalToolbar.template;
this.log.d('Setting EXTERNAL TOOLBAR'); this.log.d('Setting EXTERNAL TOOLBAR');
this.openviduAngularToolbarTemplate = this.externalToolbar.template;
} else { } else {
this.log.d('Setting DEFAULT TOOLBAR');
if (this.externalToolbarAdditionalButtons) { if (this.externalToolbarAdditionalButtons) {
this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL BUTTONS'); this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL BUTTONS');
this.openviduAngularToolbarAdditionalButtonsTemplate = this.externalToolbarAdditionalButtons.template; this.openviduAngularToolbarAdditionalButtonsTemplate = this.externalToolbarAdditionalButtons.template;
} }
if (this.externalToolbarAdditionalPanelButtons) {
this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL PANEL BUTTONS');
this.openviduAngularToolbarAdditionalPanelButtonsTemplate = this.externalToolbarAdditionalPanelButtons.template;
}
this.openviduAngularToolbarTemplate = this.defaultToolbarTemplate; this.openviduAngularToolbarTemplate = this.defaultToolbarTemplate;
this.log.d('Setting DEFAULT TOOLBAR');
} }
if (this.externalPanel) { if (this.externalPanel) {
this.openviduAngularPanelTemplate = this.externalPanel.template;
this.log.d('Setting EXTERNAL PANEL'); this.log.d('Setting EXTERNAL PANEL');
this.openviduAngularPanelTemplate = this.externalPanel.template;
} else { } else {
this.log.d('Setting DEFAULT PANEL'); this.log.d('Setting DEFAULT PANEL');
@ -369,8 +393,8 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
} else { } else {
this.log.d('Setting DEFAULT PARTICIPANTS PANEL'); this.log.d('Setting DEFAULT PARTICIPANTS PANEL');
if (this.externalParticipantPanelItem) { if (this.externalParticipantPanelItem) {
this.openviduAngularParticipantPanelItemTemplate = this.externalParticipantPanelItem.template;
this.log.d('Setting EXTERNAL P ITEM'); this.log.d('Setting EXTERNAL P ITEM');
this.openviduAngularParticipantPanelItemTemplate = this.externalParticipantPanelItem.template;
} else { } else {
if (this.externalParticipantPanelItemElements) { if (this.externalParticipantPanelItemElements) {
this.log.d('Setting EXTERNAL PARTICIPANT PANEL ITEM ELEMENT'); this.log.d('Setting EXTERNAL PARTICIPANT PANEL ITEM ELEMENT');
@ -383,27 +407,32 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
} }
if (this.externalChatPanel) { if (this.externalChatPanel) {
this.openviduAngularChatPanelTemplate = this.externalChatPanel.template;
this.log.d('Setting EXTERNAL CHAT PANEL'); this.log.d('Setting EXTERNAL CHAT PANEL');
this.openviduAngularChatPanelTemplate = this.externalChatPanel.template;
} else { } else {
this.openviduAngularChatPanelTemplate = this.defaultChatPanelTemplate;
this.log.d('Setting DEFAULT CHAT PANEL'); this.log.d('Setting DEFAULT CHAT PANEL');
this.openviduAngularChatPanelTemplate = this.defaultChatPanelTemplate;
}
if (this.externalAdditionalPanels) {
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
this.openviduAngularAdditionalPanelsTemplate = this.externalAdditionalPanels.template;
} }
this.openviduAngularPanelTemplate = this.defaultPanelTemplate; this.openviduAngularPanelTemplate = this.defaultPanelTemplate;
} }
if (this.externalLayout) { if (this.externalLayout) {
this.openviduAngularLayoutTemplate = this.externalLayout.template;
this.log.d('Setting EXTERNAL LAYOUT'); this.log.d('Setting EXTERNAL LAYOUT');
this.openviduAngularLayoutTemplate = this.externalLayout.template;
} else { } else {
this.log.d('Setting DEAFULT LAYOUT'); this.log.d('Setting DEAFULT LAYOUT');
if (this.externalStream) { if (this.externalStream) {
this.openviduAngularStreamTemplate = this.externalStream.template;
this.log.d('Setting EXTERNAL STREAM'); this.log.d('Setting EXTERNAL STREAM');
this.openviduAngularStreamTemplate = this.externalStream.template;
} else { } else {
this.openviduAngularStreamTemplate = this.defaultStreamTemplate;
this.log.d('Setting DEFAULT STREAM'); this.log.d('Setting DEFAULT STREAM');
this.openviduAngularStreamTemplate = this.defaultStreamTemplate;
} }
this.openviduAngularLayoutTemplate = this.defaultLayoutTemplate; this.openviduAngularLayoutTemplate = this.defaultLayoutTemplate;
} }

View File

@ -8,7 +8,9 @@ import {
ParticipantsPanelDirective, ParticipantsPanelDirective,
StreamDirective, StreamDirective,
ToolbarAdditionalButtonsDirective, ToolbarAdditionalButtonsDirective,
ToolbarDirective ToolbarDirective,
ToolbarAdditionalPanelButtonsDirective,
AdditionalPanelsDirective
} from './openvidu-angular.directive'; } from './openvidu-angular.directive';
@NgModule({ @NgModule({
@ -16,22 +18,26 @@ import {
ChatPanelDirective, ChatPanelDirective,
LayoutDirective, LayoutDirective,
PanelDirective, PanelDirective,
AdditionalPanelsDirective,
ParticipantPanelItemDirective, ParticipantPanelItemDirective,
ParticipantsPanelDirective, ParticipantsPanelDirective,
StreamDirective, StreamDirective,
ToolbarDirective, ToolbarDirective,
ToolbarAdditionalButtonsDirective, ToolbarAdditionalButtonsDirective,
ToolbarAdditionalPanelButtonsDirective,
ParticipantPanelItemElementsDirective ParticipantPanelItemElementsDirective
], ],
exports: [ exports: [
ChatPanelDirective, ChatPanelDirective,
LayoutDirective, LayoutDirective,
PanelDirective, PanelDirective,
AdditionalPanelsDirective,
ParticipantPanelItemDirective, ParticipantPanelItemDirective,
ParticipantsPanelDirective, ParticipantsPanelDirective,
StreamDirective, StreamDirective,
ToolbarDirective, ToolbarDirective,
ToolbarAdditionalButtonsDirective, ToolbarAdditionalButtonsDirective,
ToolbarAdditionalPanelButtonsDirective,
ParticipantPanelItemElementsDirective ParticipantPanelItemElementsDirective
] ]
}) })

View File

@ -124,11 +124,35 @@ export class ToolbarAdditionalButtonsDirective {
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {} constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
} }
@Directive({
selector: '[ovToolbarAdditionalPanelButtons]'
})
export class ToolbarAdditionalPanelButtonsDirective {
/**
* @ignore
*/
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({ @Directive({
selector: '[ovPanel]' selector: '[ovPanel]'
}) })
export class PanelDirective { export class PanelDirective {
/**
* @ignore
*/
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
}
@Directive({
selector: '[ovAdditionalPanels]'
})
export class AdditionalPanelsDirective {
/**
* @ignore
*/
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {} constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
} }

View File

@ -1,7 +1,4 @@
/** export enum PanelType {
* @internal
*/
export enum MenuType {
CHAT = 'chat', CHAT = 'chat',
PARTICIPANTS = 'participants' PARTICIPANTS = 'participants'
} }

View File

@ -12,7 +12,7 @@ import { LoggerService } from '../logger/logger.service';
import { Signal } from '../../models/signal.model'; import { Signal } from '../../models/signal.model';
import { PanelService } from '../panel/panel.service'; import { PanelService } from '../panel/panel.service';
import { ParticipantService } from '../participant/participant.service'; import { ParticipantService } from '../participant/participant.service';
import { MenuType } from '../../models/menu.model'; import { PanelType } from '../../models/panel.model';
/** /**
* @internal * @internal
@ -77,6 +77,6 @@ export class ChatService {
} }
protected launchNotification(options: INotificationOptions) { protected launchNotification(options: INotificationOptions) {
this.actionService.launchNotification(options, this.panelService.togglePanel.bind(this.panelService, MenuType.CHAT)); this.actionService.launchNotification(options, this.panelService.togglePanel.bind(this.panelService, PanelType.CHAT));
} }
} }

View File

@ -1,69 +1,78 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { ILogger } from '../../models/logger.model'; import { ILogger } from '../../models/logger.model';
import { MenuType } from '../../models/menu.model'; import { PanelType } from '../../models/panel.model';
import { LoggerService } from '../logger/logger.service'; import { LoggerService } from '../logger/logger.service';
/**
* @internal
*/
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class PanelService { export class PanelService {
panelOpenedObs: Observable<{ opened: boolean; type?: MenuType }>; panelOpenedObs: Observable<{ opened: boolean; type?: PanelType | string }>;
protected log: ILogger; protected log: ILogger;
protected isChatPanelOpened: boolean = false; protected isChatOpened: boolean = false;
protected isParticipantsPanelOpened: boolean = false; protected isParticipantsOpened: boolean = false;
protected _panelOpened = <BehaviorSubject<{ opened: boolean; type?: MenuType }>>new BehaviorSubject({ opened: false }); private isExternalOpened: boolean = false;
private externalType: string;
protected _panelOpened = <BehaviorSubject<{ opened: boolean; type?: PanelType | string }>>new BehaviorSubject({ opened: false });
/**
* @internal
*/
constructor(protected loggerSrv: LoggerService) { constructor(protected loggerSrv: LoggerService) {
this.log = this.loggerSrv.get('PanelService'); this.log = this.loggerSrv.get('PanelService');
this.panelOpenedObs = this._panelOpened.asObservable(); this.panelOpenedObs = this._panelOpened.asObservable();
} }
isPanelOpened(): boolean { togglePanel(type: PanelType | string) {
return this.isChatOpened() || this.isParticipantsOpened();
}
togglePanel(type: MenuType) {
this.log.d(`Toggling ${type} menu`); this.log.d(`Toggling ${type} menu`);
if (type === MenuType.CHAT) { let opened: boolean;
if (this.isChatPanelOpened) { if (type === PanelType.CHAT) {
// Close chat and side menu this.isChatOpened = !this.isChatOpened;
this.isChatPanelOpened = false; this.isParticipantsOpened = false;
this._panelOpened.next({ opened: false }); this.isExternalOpened = false;
} else { opened = this.isChatOpened;
// Open chat } else if (type === PanelType.PARTICIPANTS) {
this.isChatPanelOpened = true; this.isParticipantsOpened = !this.isParticipantsOpened;
this.isParticipantsPanelOpened = false; this.isChatOpened = false;
this._panelOpened.next({ opened: true, type: MenuType.CHAT }); this.isExternalOpened = false;
} opened = this.isParticipantsOpened;
} else if (type === MenuType.PARTICIPANTS) { } else {
if (this.isParticipantsPanelOpened) { this.log.d('Toggling external panel');
// Close participants menu and side menu this.isChatOpened = false;
this.isParticipantsPanelOpened = false; this.isParticipantsOpened = false;
this._panelOpened.next({ opened: false }); // Open when is close or is opened with another type
} else { this.isExternalOpened = !this.isExternalOpened || this.externalType !== type;
// Open participants menu this.externalType = !this.isExternalOpened ? '' : type;
this.isParticipantsPanelOpened = true; opened = this.isExternalOpened;
this.isChatPanelOpened = false;
this._panelOpened.next({ opened: true, type: MenuType.PARTICIPANTS });
}
} }
this._panelOpened.next({ opened, type });
} }
closeMenu() { /**
this.isParticipantsPanelOpened = false; * @internal
this.isChatPanelOpened = false; */
isPanelOpened(): boolean {
return this.isChatPanelOpened() || this.isParticipantsPanelOpened() || this.isExternalPanelOpened();
}
closePanel(): void {
this.isParticipantsOpened = false;
this.isChatOpened = false;
this.isExternalOpened = false;
this._panelOpened.next({ opened: false }); this._panelOpened.next({ opened: false });
} }
isChatOpened() { isChatPanelOpened(): boolean {
return this.isChatPanelOpened; return this.isChatOpened;
} }
isParticipantsOpened() { isParticipantsPanelOpened(): boolean {
return this.isParticipantsPanelOpened; return this.isParticipantsOpened;
}
private isExternalPanelOpened(): boolean {
return this.isExternalOpened;
} }
} }