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">
<!-- Custom local participant -->
<ng-container *ngIf="customLocalParticipantTemplate; else defaultLocalParticipant">
<ng-container *ngTemplateOutlet="customLocalParticipantTemplate"></ng-container>
</ng-container>
<div
class="OT_root OT_publisher"
id="localUser"
*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 -->
<ng-template #defaultLocalParticipant>
<div
class="OT_root OT_publisher"
id="localUser"
*ngFor="let connection of localParticipant | connections"
[ngClass]="{ OV_small: !connection.streamManager?.stream?.videoActive }"
>
<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
*ngFor="let connection of remoteParticipants | connections"
class="OT_root OT_publisher"
id="remote-participant"
[ngClass]="{ OV_small: !connection.streamManager?.stream?.videoActive }"
>
<ng-container *ngTemplateOutlet="streamTemplate; context: { stream: connection }"></ng-container>
</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 { ParticipantService } from '../../services/participant/participant.service';
import { ParticipantAbstractModel } from '../../models/participant.model';
@ -10,8 +10,13 @@ import { LayoutService } from '../../services/layout/layout.service';
styleUrls: ['./layout.component.css']
})
export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
@ContentChild('customLocalParticipant', { read: TemplateRef }) customLocalParticipantTemplate: TemplateRef<any>;
@ContentChild('customRemoteParticipants', { read: TemplateRef }) customRemoteParticipantsTemplate: TemplateRef<any>;
// @ContentChild('customLocalParticipant', { read: TemplateRef }) customLocalParticipantTemplate: TemplateRef<any>;
// @ContentChild('customRemoteParticipants', { read: TemplateRef }) customRemoteParticipantsTemplate: TemplateRef<any>;
@ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>;
localParticipant: ParticipantAbstractModel;
remoteParticipants: ParticipantAbstractModel[] = [];
@ -22,6 +27,8 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
constructor(protected layoutService: LayoutService, protected participantService: ParticipantService) {}
ngOnInit(): void {
this.layoutService.initialize();
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({
selector: 'ov-panel',
templateUrl: './panel.component.html',
styleUrls: ['./panel.component.css']
selector: 'ov-panel',
templateUrl: './panel.component.html',
styleUrls: ['./panel.component.css']
})
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">
<mat-sidenav-container class="sidenav-container">
<!-- OPENVIDU PANELS -->
<mat-sidenav
#sidenav
mode="{{ sidenavMode }}"
@ -10,33 +9,23 @@
fixedTopGap="0"
fixedBottomGap="0"
>
<!-- Custom menu content -->
<ng-container *ngIf="customPanelContentTemplate; else defaultPanelContent">
<ng-container *ngTemplateOutlet="customPanelContentTemplate"></ng-container>
<!-- OPENVIDU PANEL -->
<ng-container *ngIf="panelTemplate">
<ng-container *ngTemplateOutlet="panelTemplate"></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>
<!-- OPENVIDU LAYOUT -->
<mat-sidenav-content class="sidenav-main">
<div id="layout-container">
<ng-content select="[layout]"></ng-content>
</div>
<ng-container *ngIf="layoutTemplate">
<div id="layout-container">
<ng-container *ngTemplateOutlet="layoutTemplate"></ng-container>
</div>
</ng-container>
</mat-sidenav-content>
</mat-sidenav-container>
<!-- Custom toolbar -->
<!-- <ng-container *ngIf="toolbarTemplate">
<div id="toolbar-container">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
</div>
</ng-container> -->
<!-- OPENVIDU TOOLBAR -->
<ng-container *ngIf="toolbarTemplate">
<div id="footer-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 {
@ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any>;
@ContentChild('customPanelContent', { read: TemplateRef }) customPanelContentTemplate: TemplateRef<any>;
@ContentChild('customLayoutElement', { read: TemplateRef }) customLayoutElementTemplate: TemplateRef<any>;
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>;
@Input() tokens: { webcam: string; screen: string };
@Output() _session = new EventEmitter<any>();
@ -87,7 +87,7 @@ export class SessionComponent implements OnInit {
}
async ngOnInit() {
this.layoutService.initialize();
// this.layoutService.initialize();
if (this.webrtcService.getWebcamSession() === null) {
this.webrtcService.initialize();

View File

@ -52,16 +52,11 @@ export class StreamComponent implements OnInit {
// 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()
set participant(participant: StreamModel) {
this._participant = participant;
this.checkVideoSizeBigIcon(participant.videoEnlarged);
this.nicknameFormControl = new FormControl(this._participant.nickname, [Validators.maxLength(25), Validators.required]);
}

View File

@ -1,6 +1,6 @@
<div id="call-container">
<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 id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && !error">
@ -10,21 +10,88 @@
<div id="spinner" *ngIf="joinSessionClicked && !isSessionAlive && error">
<mat-icon class="error-icon">error</mat-icon>
<span>{{errorMessage}}</span>
<span>{{ errorMessage }}</span>
</div>
<div id="session-container" *ngIf="joinSessionClicked && isSessionAlive && !error">
<ov-session [tokens]="_tokens">
<!-- Toolbar container injection -->
<ng-template #toolbar>
<ov-toolbar
(onCamClicked)="onCamClicked()"
(onMicClicked)="onMicClicked()"
(onScreenShareClicked)="onScreenShareClicked()"
(onSpeakerLayoutClicked)="onSpeakerLayoutClicked()"
(onLeaveSessionClicked)="onLeaveSessionClicked()"
></ov-toolbar>
<!-- Custom toolbar -->
<ng-container *ngIf="toolbarTemplate; else defaultToolbar">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
</ng-container>
<!-- Default toolbar if custom toolbar is not injected -->
<ng-template #defaultToolbar>
<ov-toolbar></ov-toolbar>
</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>
</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';
@Component({
@ -7,12 +7,22 @@ import { RestService } from '../../services/rest/rest.service';
styleUrls: ['./videoconference.component.css']
})
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() userName: string;
@Input() openviduServerUrl: string;
@Input() openviduSecret: string;
@Input() tokens: { webcam: string; screen: string };
@Output() onJoinClicked = new EventEmitter<any>();
@Output() onCloseClicked = new EventEmitter<any>();
joinSessionClicked: boolean = false;
closeClicked: boolean = false;
isSessionAlive: boolean = false;
@ -24,36 +34,38 @@ export class VideoconferenceComponent implements OnInit {
ngOnInit() {}
async onJoinClicked() {
if (!this.tokens || (!this.tokens?.webcam && !this.tokens?.screen)) {
//No tokens received
async _onJoinClicked() {
if (!!this.sessionName && !!this.openviduServerUrl && !!this.openviduSecret) {
// Generate tokens
this._tokens = {
webcam: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret),
screen: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret)
};
} else {
// No tokens received and can't generate them
this.error = true;
this.errorMessage = `Cannot access to OpenVidu Server with url '${this.openviduServerUrl}' to genere tokens for session '${this.sessionName}'`;
throw this.errorMessage;
}
} else if (!this.tokens?.webcam || !this.tokens?.screen) {
// 1 token received
const aditionalToken = await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret);
this._tokens = {
webcam: !!this.tokens.webcam ? this.tokens.webcam : aditionalToken,
screen: !!this.tokens.screen ? this.tokens.screen : aditionalToken
};
} else {
// 2 tokens received.
this._tokens = {
webcam: this.tokens.webcam,
screen: this.tokens.screen
};
}
this.onJoinClicked.emit();
// if (!this.tokens || (!this.tokens?.webcam && !this.tokens?.screen)) {
// //No tokens received
// if (!!this.sessionName && !!this.openviduServerUrl && !!this.openviduSecret) {
// // Generate tokens
// this._tokens = {
// webcam: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret),
// screen: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret)
// };
// } else {
// // No tokens received and can't generate them
// this.error = true;
// this.errorMessage = `Cannot access to OpenVidu Server with url '${this.openviduServerUrl}' to genere tokens for session '${this.sessionName}'`;
// throw this.errorMessage;
// }
// } else if (!this.tokens?.webcam || !this.tokens?.screen) {
// // 1 token received
// const aditionalToken = await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret);
// this._tokens = {
// webcam: !!this.tokens.webcam ? this.tokens.webcam : aditionalToken,
// screen: !!this.tokens.screen ? this.tokens.screen : aditionalToken
// };
// } else {
// // 2 tokens received.
// this._tokens = {
// webcam: this.tokens.webcam,
// screen: this.tokens.screen
// };
// }
this.joinSessionClicked = 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">
<ov-user-settings (onJoinClicked)="onJoinClicked()" (onCloseClicked)="onCloseClicked()"></ov-user-settings>
</div>
@ -17,4 +17,39 @@
<ov-layout layout></ov-layout>
</ov-session>
</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() {}
onCamClicked() {}
onCamClicked() {
console.log('APP: CAM CLIKED')
}
onScreenShareClicked() {}