openvidu-components: Updated the dynamic components injection

Allowed the custom components injection from the view instead of the config file.
pull/707/head
csantosm 2022-02-03 17:08:23 +01:00
parent bfd21ecd1e
commit 00087a7dc7
11 changed files with 238 additions and 115 deletions

View File

@ -1,35 +1,23 @@
<div id="layout" class="bounds"> <div id="layout" class="bounds">
<!-- Custom local participant --> <div
<ng-container *ngIf="customLocalParticipantTemplate; else defaultLocalParticipant"> class="OT_root OT_publisher"
<ng-container *ngTemplateOutlet="customLocalParticipantTemplate"></ng-container> id="localUser"
</ng-container> *ngFor="let connection of localParticipant | connections"
[ngClass]="{ OV_small: !connection.streamManager?.stream?.videoActive }"
>
<ng-container *ngTemplateOutlet="streamTemplate; context: { stream: connection }"></ng-container>
</div>
<!-- <ng-template #stream let-stream="stream">
<p>{{prueba.videoEnlarged}}</p>
<ov-stream [participant]="prueba"></ov-stream>
</ng-template> -->
<!-- Default local participant if custom participant is not injected --> <div
<ng-template #defaultLocalParticipant> *ngFor="let connection of remoteParticipants | connections"
<div class="OT_root OT_publisher"
class="OT_root OT_publisher" id="remote-participant"
id="localUser" [ngClass]="{ OV_small: !connection.streamManager?.stream?.videoActive }"
*ngFor="let connection of localParticipant | connections" >
[ngClass]="{ OV_small: !connection.streamManager?.stream?.videoActive }" <ng-container *ngTemplateOutlet="streamTemplate; context: { stream: connection }"></ng-container>
> </div>
<ov-stream [participant]="connection" [videoEnlarged]="connection.videoEnlarged"></ov-stream>
</div>
</ng-template>
<!-- Custom remote participant -->
<ng-container *ngIf="customRemoteParticipantsTemplate; else defaultRemoteParticipants">
<ng-container *ngTemplateOutlet="customRemoteParticipantsTemplate"></ng-container>
</ng-container>
<!-- Default remote participants if custom participants is not injected -->
<ng-template #defaultRemoteParticipants>
<div
*ngFor="let connection of remoteParticipants | connections"
class="OT_root OT_publisher"
id="remote-participant"
[ngClass]="{ OV_small: !connection.streamManager?.stream?.videoActive }"
>
<ov-stream [participant]="connection" [videoEnlarged]="connection.videoEnlarged"></ov-stream>
</div>
</ng-template>
</div> </div>

View File

@ -1,4 +1,4 @@
import { AfterViewInit, Component, ContentChild, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { AfterViewInit, Component, ComponentRef, ContentChild, Directive, Input, OnDestroy, OnInit, TemplateRef, Type, ViewChild, ViewContainerRef } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
import { ParticipantAbstractModel } from '../../models/participant.model'; import { ParticipantAbstractModel } from '../../models/participant.model';
@ -10,8 +10,13 @@ import { LayoutService } from '../../services/layout/layout.service';
styleUrls: ['./layout.component.css'] styleUrls: ['./layout.component.css']
}) })
export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit { export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
@ContentChild('customLocalParticipant', { read: TemplateRef }) customLocalParticipantTemplate: TemplateRef<any>; // @ContentChild('customLocalParticipant', { read: TemplateRef }) customLocalParticipantTemplate: TemplateRef<any>;
@ContentChild('customRemoteParticipants', { read: TemplateRef }) customRemoteParticipantsTemplate: TemplateRef<any>; // @ContentChild('customRemoteParticipants', { read: TemplateRef }) customRemoteParticipantsTemplate: TemplateRef<any>;
@ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>;
localParticipant: ParticipantAbstractModel; localParticipant: ParticipantAbstractModel;
remoteParticipants: ParticipantAbstractModel[] = []; remoteParticipants: ParticipantAbstractModel[] = [];
@ -22,6 +27,8 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
constructor(protected layoutService: LayoutService, protected participantService: ParticipantService) {} constructor(protected layoutService: LayoutService, protected participantService: ParticipantService) {}
ngOnInit(): void { ngOnInit(): void {
this.layoutService.initialize();
this.subscribeToUsers(); this.subscribeToUsers();
} }

View File

@ -1 +1,9 @@
<p>panel works!</p> <!-- Custom chat panel -->
<ng-container *ngIf="chatPanelTemplate && isChatPanelOpened">
<ng-container *ngTemplateOutlet="chatPanelTemplate"></ng-container>
</ng-container>
<!-- Custom participants panel -->
<ng-container *ngIf="participantsPanelTemplate && isParticipantsPanelOpened">
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container>
</ng-container>

View File

@ -1,15 +1,35 @@
import { Component, OnInit } from '@angular/core'; import { Component, ContentChild, OnInit, TemplateRef } from '@angular/core';
import { skip, Subscription } from 'rxjs';
import { MenuType } from '../../models/menu.model';
import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.service';
@Component({ @Component({
selector: 'ov-panel', selector: 'ov-panel',
templateUrl: './panel.component.html', templateUrl: './panel.component.html',
styleUrls: ['./panel.component.css'] styleUrls: ['./panel.component.css']
}) })
export class PanelComponent implements OnInit { export class PanelComponent implements OnInit {
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>;
@ContentChild('chatPanel', { read: TemplateRef }) chatPanelTemplate: TemplateRef<any>;
constructor() { } isParticipantsPanelOpened: boolean;
isChatPanelOpened: boolean;
menuSubscription: Subscription;
constructor(protected menuService: SidenavMenuService) {}
ngOnInit(): void { ngOnInit(): void {
} this.subscribeToPanelToggling();
}
subscribeToPanelToggling() {
this.menuSubscription = this.menuService.menuOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: MenuType }) => {
this.isChatPanelOpened = ev.opened && ev.type === MenuType.CHAT;
this.isParticipantsPanelOpened = ev.opened && ev.type === MenuType.PARTICIPANTS;
});
}
ngOnDestroy() {
this.isChatPanelOpened = false;
this.isParticipantsPanelOpened = false;
if (this.menuSubscription) this.menuSubscription.unsubscribe();
}
} }

View File

@ -1,6 +1,5 @@
<div id="session-container"> <div id="session-container">
<mat-sidenav-container class="sidenav-container"> <mat-sidenav-container class="sidenav-container">
<!-- OPENVIDU PANELS -->
<mat-sidenav <mat-sidenav
#sidenav #sidenav
mode="{{ sidenavMode }}" mode="{{ sidenavMode }}"
@ -10,33 +9,23 @@
fixedTopGap="0" fixedTopGap="0"
fixedBottomGap="0" fixedBottomGap="0"
> >
<!-- Custom menu content --> <!-- OPENVIDU PANEL -->
<ng-container *ngIf="customPanelContentTemplate; else defaultPanelContent"> <ng-container *ngIf="panelTemplate">
<ng-container *ngTemplateOutlet="customPanelContentTemplate"></ng-container> <ng-container *ngTemplateOutlet="panelTemplate"></ng-container>
</ng-container> </ng-container>
<!-- Default menu content if custom menu content is not injected -->
<ng-template #defaultPanelContent>
<ov-chat-panel *ngIf="isChatPanelOpened"></ov-chat-panel>
<ov-participants-panel *ngIf="isParticipantsPanelOpened"></ov-participants-panel>
</ng-template>
</mat-sidenav> </mat-sidenav>
<!-- OPENVIDU LAYOUT --> <!-- OPENVIDU LAYOUT -->
<mat-sidenav-content class="sidenav-main"> <mat-sidenav-content class="sidenav-main">
<div id="layout-container"> <ng-container *ngIf="layoutTemplate">
<ng-content select="[layout]"></ng-content> <div id="layout-container">
</div> <ng-container *ngTemplateOutlet="layoutTemplate"></ng-container>
</div>
</ng-container>
</mat-sidenav-content> </mat-sidenav-content>
</mat-sidenav-container> </mat-sidenav-container>
<!-- Custom toolbar --> <!-- OPENVIDU TOOLBAR -->
<!-- <ng-container *ngIf="toolbarTemplate">
<div id="toolbar-container">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
</div>
</ng-container> -->
<ng-container *ngIf="toolbarTemplate"> <ng-container *ngIf="toolbarTemplate">
<div id="footer-container"> <div id="footer-container">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container> <ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>

View File

@ -26,8 +26,8 @@ import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.ser
}) })
export class SessionComponent implements OnInit { export class SessionComponent implements OnInit {
@ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any>; @ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any>;
@ContentChild('customPanelContent', { read: TemplateRef }) customPanelContentTemplate: TemplateRef<any>; @ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
@ContentChild('customLayoutElement', { read: TemplateRef }) customLayoutElementTemplate: TemplateRef<any>; @ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>;
@Input() tokens: { webcam: string; screen: string }; @Input() tokens: { webcam: string; screen: string };
@Output() _session = new EventEmitter<any>(); @Output() _session = new EventEmitter<any>();
@ -87,7 +87,7 @@ export class SessionComponent implements OnInit {
} }
async ngOnInit() { async ngOnInit() {
this.layoutService.initialize(); // this.layoutService.initialize();
if (this.webrtcService.getWebcamSession() === null) { if (this.webrtcService.getWebcamSession() === null) {
this.webrtcService.initialize(); this.webrtcService.initialize();

View File

@ -52,16 +52,11 @@ export class StreamComponent implements OnInit {
// this.isFullscreenEnabled = !this.isFullscreenEnabled; // this.isFullscreenEnabled = !this.isFullscreenEnabled;
// } // }
// Has been mandatory fullscreen Input because of Input user did not fire changing
// the fullscreen user property in publisherStartSpeaking event in SessionComponent
@Input()
set videoEnlarged(enlarged: boolean) {
this.checkVideoSizeBigIcon(enlarged);
}
@Input() @Input()
set participant(participant: StreamModel) { set participant(participant: StreamModel) {
this._participant = participant; this._participant = participant;
this.checkVideoSizeBigIcon(participant.videoEnlarged);
this.nicknameFormControl = new FormControl(this._participant.nickname, [Validators.maxLength(25), Validators.required]); this.nicknameFormControl = new FormControl(this._participant.nickname, [Validators.maxLength(25), Validators.required]);
} }

View File

@ -1,6 +1,6 @@
<div id="call-container"> <div id="call-container">
<div id="user-settings-container" *ngIf="!joinSessionClicked && !closeClicked"> <div id="user-settings-container" *ngIf="!joinSessionClicked && !closeClicked">
<ov-user-settings (onJoinClicked)="onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings> <ov-user-settings (onJoinClicked)="_onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings>
</div> </div>
<div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && !error"> <div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && !error">
@ -10,21 +10,88 @@
<div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && error"> <div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && error">
<mat-icon class="error-icon">error</mat-icon> <mat-icon class="error-icon">error</mat-icon>
<span>{{errorMessage}}</span> <span>{{ errorMessage }}</span>
</div> </div>
<div id="session-container" *ngIf="joinSessionClicked && isSessionAlive && !error"> <div id="session-container" *ngIf="joinSessionClicked && isSessionAlive && !error">
<ov-session [tokens]="_tokens"> <ov-session [tokens]="_tokens">
<!-- Toolbar container injection -->
<ng-template #toolbar> <ng-template #toolbar>
<ov-toolbar <!-- Custom toolbar -->
(onCamClicked)="onCamClicked()" <ng-container *ngIf="toolbarTemplate; else defaultToolbar">
(onMicClicked)="onMicClicked()" <ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
(onScreenShareClicked)="onScreenShareClicked()" </ng-container>
(onSpeakerLayoutClicked)="onSpeakerLayoutClicked()"
(onLeaveSessionClicked)="onLeaveSessionClicked()" <!-- Default toolbar if custom toolbar is not injected -->
></ov-toolbar> <ng-template #defaultToolbar>
<ov-toolbar></ov-toolbar>
</ng-template>
</ng-template> </ng-template>
<ov-layout layout></ov-layout>
<ng-template #panel>
<!-- Custom panel -->
<ng-container *ngIf="panelTemplate; else defaultPanel">
<ng-container *ngTemplateOutlet="panelTemplate"></ng-container>
</ng-container>
<!-- Default panel if custom panel is not injected -->
<ng-template #defaultPanel>
<ov-panel>
<!-- CHAT panel -->
<ng-template #chatPanel>
<ng-container *ngIf="chatPanelTemplate; else defaultChatPanel">
<ng-container *ngTemplateOutlet="chatPanelTemplate"></ng-container>
</ng-container>
<ng-template #defaultChatPanel>
<ov-chat-panel></ov-chat-panel>
</ng-template>
</ng-template>
<!-- PARTICIPANTS panel -->
<ng-template #participantsPanel>
<ng-container *ngIf="participantsPanelTemplate; else defaultParticipantsPanel">
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container>
</ng-container>
<ng-template #defaultParticipantsPanel>
<ov-participants-panel></ov-participants-panel>
</ng-template>
</ng-template>
</ov-panel>
</ng-template>
</ng-template>
<!-- Layout container injection -->
<ng-template #layout>
<!-- Custom layout -->
<ng-container *ngIf="layoutTemplate; else defaultLayout">
<ng-container *ngTemplateOutlet="layoutTemplate"></ng-container>
</ng-container>
<!-- Default layout if custom layout is not injected -->
<ng-template #defaultLayout>
<ov-layout>
<ng-template #stream let-stream="stream">
<!-- Custom stream component -->
<!-- We must to bind a context for the 'participant' input property -->
<ng-container *ngIf="streamTemplate; else defaultStream">
<ng-container *ngTemplateOutlet="streamTemplate;context:{stream:stream}"></ng-container>
</ng-container>
<!-- Default stream component if custom component is not injected -->
<!-- We must to bind a context for the 'participant' input property -->
<ng-template #defaultStream>
<ov-stream [participant]="stream"></ov-stream>
</ng-template>
</ng-template>
</ov-layout>
</ng-template>
</ng-template>
</ov-session> </ov-session>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';
import { RestService } from '../../services/rest/rest.service'; import { RestService } from '../../services/rest/rest.service';
@Component({ @Component({
@ -7,12 +7,22 @@ import { RestService } from '../../services/rest/rest.service';
styleUrls: ['./videoconference.component.css'] styleUrls: ['./videoconference.component.css']
}) })
export class VideoconferenceComponent implements OnInit { export class VideoconferenceComponent implements OnInit {
@ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any>;
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>;
@ContentChild('chatPanel', { read: TemplateRef }) chatPanelTemplate: TemplateRef<any>;
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>;
@ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>;
@Input() sessionName: string; @Input() sessionName: string;
@Input() userName: string; @Input() userName: string;
@Input() openviduServerUrl: string; @Input() openviduServerUrl: string;
@Input() openviduSecret: string; @Input() openviduSecret: string;
@Input() tokens: { webcam: string; screen: string }; @Input() tokens: { webcam: string; screen: string };
@Output() onJoinClicked = new EventEmitter<any>();
@Output() onCloseClicked = new EventEmitter<any>();
joinSessionClicked: boolean = false; joinSessionClicked: boolean = false;
closeClicked: boolean = false; closeClicked: boolean = false;
isSessionAlive: boolean = false; isSessionAlive: boolean = false;
@ -24,36 +34,38 @@ export class VideoconferenceComponent implements OnInit {
ngOnInit() {} ngOnInit() {}
async onJoinClicked() { async _onJoinClicked() {
if (!this.tokens || (!this.tokens?.webcam && !this.tokens?.screen)) {
//No tokens received
if (!!this.sessionName && !!this.openviduServerUrl && !!this.openviduSecret) { this.onJoinClicked.emit();
// Generate tokens // if (!this.tokens || (!this.tokens?.webcam && !this.tokens?.screen)) {
this._tokens = { // //No tokens received
webcam: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret),
screen: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret) // if (!!this.sessionName && !!this.openviduServerUrl && !!this.openviduSecret) {
}; // // Generate tokens
} else { // this._tokens = {
// No tokens received and can't generate them // webcam: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret),
this.error = true; // screen: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret)
this.errorMessage = `Cannot access to OpenVidu Server with url '${this.openviduServerUrl}' to genere tokens for session '${this.sessionName}'`; // };
throw this.errorMessage; // } else {
} // // No tokens received and can't generate them
} else if (!this.tokens?.webcam || !this.tokens?.screen) { // this.error = true;
// 1 token received // this.errorMessage = `Cannot access to OpenVidu Server with url '${this.openviduServerUrl}' to genere tokens for session '${this.sessionName}'`;
const aditionalToken = await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret); // throw this.errorMessage;
this._tokens = { // }
webcam: !!this.tokens.webcam ? this.tokens.webcam : aditionalToken, // } else if (!this.tokens?.webcam || !this.tokens?.screen) {
screen: !!this.tokens.screen ? this.tokens.screen : aditionalToken // // 1 token received
}; // const aditionalToken = await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret);
} else { // this._tokens = {
// 2 tokens received. // webcam: !!this.tokens.webcam ? this.tokens.webcam : aditionalToken,
this._tokens = { // screen: !!this.tokens.screen ? this.tokens.screen : aditionalToken
webcam: this.tokens.webcam, // };
screen: this.tokens.screen // } else {
}; // // 2 tokens received.
} // this._tokens = {
// webcam: this.tokens.webcam,
// screen: this.tokens.screen
// };
// }
this.joinSessionClicked = true; this.joinSessionClicked = true;
this.isSessionAlive = true; this.isSessionAlive = true;
} }

View File

@ -1,4 +1,4 @@
<div id="call-container"> <!-- <div id="call-container">
<div id="userSettings" *ngIf="!joinSessionClicked && !closeClicked || !isSessionAlive"> <div id="userSettings" *ngIf="!joinSessionClicked && !closeClicked || !isSessionAlive">
<ov-user-settings (onJoinClicked)="onJoinClicked()" (onCloseClicked)="onCloseClicked()"></ov-user-settings> <ov-user-settings (onJoinClicked)="onJoinClicked()" (onCloseClicked)="onCloseClicked()"></ov-user-settings>
</div> </div>
@ -17,4 +17,39 @@
<ov-layout layout></ov-layout> <ov-layout layout></ov-layout>
</ov-session> </ov-session>
</div> </div>
</div> </div> -->
<ov-videoconference (onJoinClicked)="onJoinClicked()" [tokens]="tokens">
<!-- <ng-template #toolbar>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #layout>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #panel>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #chatPanel>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #participantsPanel>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #stream let-stream="stream">
<ov-stream postion="top" [participant]="stream">
<button network-quality> hola</button>
</ov-stream>
</ng-template> -->
</ov-videoconference>

View File

@ -37,7 +37,9 @@ export class CallComponent implements OnInit {
onMicClicked() {} onMicClicked() {}
onCamClicked() {} onCamClicked() {
console.log('APP: CAM CLIKED')
}
onScreenShareClicked() {} onScreenShareClicked() {}