openvidu-components: Updated projection strategy

Replaces ng-templates by a custom structural directive
pull/707/head
csantosm 2022-02-11 13:18:50 +01:00
parent bb8f0b752f
commit 2d293a689e
12 changed files with 125 additions and 167 deletions

View File

@ -5,12 +5,8 @@
*ngFor="let stream of localParticipant | connections" *ngFor="let stream of localParticipant | connections"
[ngClass]="{ OV_small: !stream.streamManager?.stream?.videoActive }" [ngClass]="{ OV_small: !stream.streamManager?.stream?.videoActive }"
> >
<ng-container *ngTemplateOutlet="streamTemplate; context: { stream: stream }"></ng-container> <ng-container *ngTemplateOutlet="streamTemplate; context: { $implicit: stream }"></ng-container>
</div> </div>
<!-- <ng-template #stream let-stream="stream">
<p>{{prueba.videoEnlarged}}</p>
<ov-stream [participant]="prueba"></ov-stream>
</ng-template> -->
<div <div
*ngFor="let stream of remoteParticipants | connections" *ngFor="let stream of remoteParticipants | connections"
@ -18,6 +14,6 @@
id="remote-participant" id="remote-participant"
[ngClass]="{ OV_small: !stream.streamManager?.stream?.videoActive }" [ngClass]="{ OV_small: !stream.streamManager?.stream?.videoActive }"
> >
<ng-container *ngTemplateOutlet="streamTemplate; context: { stream: stream }"></ng-container> <ng-container *ngTemplateOutlet="streamTemplate; context: { $implicit: stream }"></ng-container>
</div> </div>
</div> </div>

View File

@ -1,9 +1,6 @@
<!-- Custom chat panel --> <!-- CHAT panel -->
<ng-container *ngIf="chatPanelTemplate && isChatPanelOpened"> <ng-content select="[chatPanel]" *ngIf="isChatPanelOpened"></ng-content>
<ng-container *ngTemplateOutlet="chatPanelTemplate"></ng-container>
</ng-container> <!-- PARTICIPANTS panel -->
<ng-content select="[participantsPanel]" *ngIf="isParticipantsPanelOpened"></ng-content>
<!-- Custom participants panel -->
<ng-container *ngIf="participantsPanelTemplate && isParticipantsPanelOpened">
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container>
</ng-container>

View File

@ -9,14 +9,14 @@
fixedTopGap="0" fixedTopGap="0"
fixedBottomGap="0" fixedBottomGap="0"
> >
<!-- OPENVIDU PANEL --> <!-- OPENVIDU PANEL -->
<ng-container *ngIf="panelTemplate"> <ng-content select="[panel]"></ng-content>
<ng-container *ngTemplateOutlet="panelTemplate"></ng-container>
</ng-container>
</mat-sidenav> </mat-sidenav>
<!-- OPENVIDU LAYOUT -->
<mat-sidenav-content class="sidenav-main"> <mat-sidenav-content class="sidenav-main">
<!-- OPENVIDU LAYOUT -->
<ng-container *ngIf="layoutTemplate"> <ng-container *ngIf="layoutTemplate">
<div id="layout-container"> <div id="layout-container">
<ng-container *ngTemplateOutlet="layoutTemplate"></ng-container> <ng-container *ngTemplateOutlet="layoutTemplate"></ng-container>
@ -26,9 +26,13 @@
</mat-sidenav-container> </mat-sidenav-container>
<!-- OPENVIDU TOOLBAR --> <!-- OPENVIDU TOOLBAR -->
<ng-container *ngIf="toolbarTemplate"> <div id="footer-container">
<div id="footer-container"> <span #toolbarRef>
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container> <!-- Custom toolbar -->
</div> <ng-content select="[toolbar]"></ng-content>
</ng-container> </span>
<!-- Default toolbar if custom toolbar is not injected -->
<ov-toolbar *ngIf="toolbarRef.childNodes.length === 0"></ov-toolbar>
</div>
</div> </div>

View File

@ -24,9 +24,7 @@ import { SidenavMenuService } from '../../services/sidenav-menu/sidenav-menu.ser
styleUrls: ['./session.component.css'] styleUrls: ['./session.component.css']
}) })
export class SessionComponent implements OnInit, AfterViewInit { export class SessionComponent implements OnInit, AfterViewInit {
@ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any>;
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>; @ContentChild('layout', { read: TemplateRef }) layoutTemplate: 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>();

View File

@ -15,83 +15,54 @@
<div id="session-container" *ngIf="joinSessionClicked && isSessionAlive && !error"> <div id="session-container" *ngIf="joinSessionClicked && isSessionAlive && !error">
<ov-session [tokens]="_tokens"> <ov-session [tokens]="_tokens">
<ng-content select="[toolbar]" toolbar></ng-content>
<!-- Toolbar container injection --> <!-- OPENVIDU PANEL -->
<ng-template #toolbar> <span #panelRef panel>
<!-- 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>
<ng-template #panel>
<!-- Custom panel --> <!-- Custom panel -->
<ng-container *ngIf="panelTemplate; else defaultPanel"> <ng-content select="[panel]"></ng-content>
<ng-container *ngTemplateOutlet="panelTemplate"></ng-container> </span>
</ng-container>
<!-- Default panel if custom panel is not injected --> <!-- Default panel if the custom one is not injected -->
<ng-template #defaultPanel> <ov-panel *ngIf="panelRef.childNodes.length === 0" panel>
<ov-panel> <span #chatPanelRef chatPanel>
<!-- CHAT panel --> <!-- Custom CHAT panel -->
<ng-template #chatPanel> <ng-content select="[chatPanel]"></ng-content>
<ng-container *ngIf="chatPanelTemplate; else defaultChatPanel"> </span>
<ng-container *ngTemplateOutlet="chatPanelTemplate"></ng-container>
</ng-container>
<ng-template #defaultChatPanel> <!-- Default CHAT PANEL if the custom one is not injected -->
<ov-chat-panel></ov-chat-panel> <ov-chat-panel *ngIf="chatPanelRef.childNodes.length === 0" chatPanel></ov-chat-panel>
</ng-template>
</ng-template>
<!-- PARTICIPANTS panel --> <span #participantsPanelRef participantsPanel>
<ng-template #participantsPanel> <!-- Custom PARTICIPANTS panel -->
<ng-container *ngIf="participantsPanelTemplate; else defaultParticipantsPanel"> <ng-content select="[participantsPanel]"></ng-content>
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container> </span>
</ng-container>
<ng-template #defaultParticipantsPanel>
<ov-participants-panel></ov-participants-panel>
</ng-template>
</ng-template>
</ov-panel>
</ng-template>
</ng-template> <!-- Default PARTICIPANTS PANEL if the custom one is not injected -->
<ov-participants-panel *ngIf="participantsPanelRef.childNodes.length === 0" participantsPanel></ov-participants-panel>
</ov-panel>
<!-- Layout container injection -->
<ng-template #layout> <ng-template #layout>
<!-- Custom layout --> <!-- Custom layout -->
<ng-container *ngIf="layoutTemplate; else defaultLayout"> <span #layoutRef layout>
<ng-container *ngTemplateOutlet="layoutTemplate"></ng-container> <ng-content select="[layout]"></ng-content>
</ng-container> </span>
<!-- Default layout if custom layout is not injected --> <!-- Default layout if custom layout is not injected -->
<ng-template #defaultLayout> <ov-layout *ngIf="layoutRef.childNodes.length === 0" layout>
<ov-layout> <ng-template #stream let-stream>
<ng-template #stream let-stream="stream"> <!-- Custom stream component -->
<!-- Custom stream component --> <ng-container *ngIf="streamTemplate; else defaultStream">
<!-- We must to bind a context for the 'participant' input property --> <ng-container *ngTemplateOutlet="streamTemplate; context: { $implicit: stream }"> </ng-container>
<ng-container *ngIf="streamTemplate; else defaultStream"> </ng-container>
<ng-container *ngTemplateOutlet="streamTemplate;context:{stream:stream}"></ng-container>
</ng-container>
<!-- Default stream component if custom component is not injected --> <!-- Default stream component if custom one is not injected -->
<!-- We must to bind a context for the 'participant' input property --> <ng-template #defaultStream>
<ng-template #defaultStream> <ov-stream [stream]="stream"></ov-stream>
<ov-stream [stream]="stream"></ov-stream>
</ng-template>
</ng-template> </ng-template>
</ov-layout> </ng-template>
</ng-template> </ov-layout>
</ng-template> </ng-template>
</ov-session> </ov-session>
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core'; import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core';
import { StreamDirective } from '../../directives/stream/stream.directive';
@Component({ @Component({
selector: 'ov-videoconference', selector: 'ov-videoconference',
@ -6,16 +7,38 @@ import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateR
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>; streamTemplate: TemplateRef<any>;
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>; // @ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
@ContentChild('chatPanel', { read: TemplateRef }) chatPanelTemplate: TemplateRef<any>;
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>; @ContentChild(StreamDirective)
@ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>; set customStream(customStream: StreamDirective) {
if (customStream) {
this.streamTemplate = customStream.template;
}
}
@Input() sessionName: string; @Input() sessionName: string;
@Input() userName: string; @Input() userName: string;
@Input()
set tokens(tokens: { webcam: string; screen: string }) {
if (!tokens || (!tokens.webcam && !tokens.screen)) {
//No tokens received
// throw new Error('No tokens received');
console.warn('No tokens received');
} else {
if (tokens.webcam || tokens.screen) {
this._tokens = {
webcam: tokens.webcam,
screen: tokens.screen
};
this.joinSessionClicked = true;
this.isSessionAlive = true;
}
}
}
// @Input() openviduServerUrl: string; // @Input() openviduServerUrl: string;
// @Input() openviduSecret: string; // @Input() openviduSecret: string;
@ -33,25 +56,6 @@ export class VideoconferenceComponent implements OnInit {
ngOnInit() {} ngOnInit() {}
@Input()
set tokens(tokens: { webcam: string; screen: string }) {
if (!tokens || (!tokens.webcam && !tokens.screen)) {
//No tokens received
// throw new Error('No tokens received');
console.warn('No tokens received');
} else {
if (tokens.webcam || tokens.screen) {
this._tokens = {
webcam: tokens.webcam,
screen: tokens.screen
};
this.joinSessionClicked = true;
this.isSessionAlive = true;
}
}
}
async _onJoinClicked() { async _onJoinClicked() {
this.onJoinClicked.emit(); this.onJoinClicked.emit();
} }

View File

@ -0,0 +1,8 @@
import { StreamDirective } from './stream.directive';
describe('StreamDirective', () => {
it('should create an instance', () => {
const directive = new StreamDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -0,0 +1,10 @@
import { Directive, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[ovStream]'
})
export class StreamDirective implements OnInit {
constructor(public template: TemplateRef<any>, public container: ViewContainerRef) {}
ngOnInit() {}
}

View File

@ -58,9 +58,13 @@ import { ParticipantItemComponent } from './components/panel/participants-panel/
import { ParticipantsPanelComponent } from './components/panel/participants-panel/participants-panel/participants-panel.component'; import { ParticipantsPanelComponent } from './components/panel/participants-panel/participants-panel/participants-panel.component';
import { VideoconferenceComponent } from './components/videoconference/videoconference.component'; import { VideoconferenceComponent } from './components/videoconference/videoconference.component';
import { PanelComponent } from './components/panel/panel.component'; import { PanelComponent } from './components/panel/panel.component';
import { StreamDirective } from './directives/stream/stream.directive';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({ @NgModule({
declarations: [ declarations: [
StreamDirective,
UserSettingsComponent, UserSettingsComponent,
VideoComponent, VideoComponent,
ToolbarComponent, ToolbarComponent,
@ -77,7 +81,7 @@ import { PanelComponent } from './components/panel/panel.component';
ParticipantItemComponent, ParticipantItemComponent,
ParticipantsPanelComponent, ParticipantsPanelComponent,
VideoconferenceComponent, VideoconferenceComponent,
PanelComponent PanelComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -132,7 +136,8 @@ import { PanelComponent } from './components/panel/panel.component';
StreamComponent, StreamComponent,
VideoComponent, VideoComponent,
ParticipantConnectionsPipe, ParticipantConnectionsPipe,
CommonModule CommonModule,
StreamDirective
], ],
entryComponents: [DialogTemplateComponent] entryComponents: [DialogTemplateComponent]
}) })

View File

@ -40,3 +40,6 @@ export * from './lib/models/notification-options.model';
// Pipes // Pipes
export * from './lib/pipes/participant-connections.pipe'; export * from './lib/pipes/participant-connections.pipe';
// Directives
export * from './lib/directives/stream/stream.directive';

View File

@ -1,61 +1,22 @@
<!-- <div id="call-container">
<div id="userSettings" *ngIf="!joinSessionClicked && !closeClicked || !isSessionAlive">
<ov-user-settings (onJoinClicked)="onJoinClicked()" (onCloseClicked)="onCloseClicked()"></ov-user-settings>
</div>
<div *ngIf="joinSessionClicked && isSessionAlive" style="height: 100%;">
<ov-session [tokens]="tokens">
<ng-template #toolbar>
<ov-toolbar
(onCamClicked)="onCamClicked()"
(onMicClicked)="onMicClicked()"
(onScreenShareClicked)="onScreenShareClicked()"
(onSpeakerLayoutClicked)="onSpeakerLayoutClicked()"
(onLeaveSessionClicked)="onLeaveSessionClicked()"
></ov-toolbar>
</ng-template>
<ov-layout layout></ov-layout>
</ov-session>
</div>
</div> -->
<ov-videoconference (onJoinClicked)="onJoinClicked()" [tokens]="tokens"> <ov-videoconference (onJoinClicked)="onJoinClicked()" [tokens]="tokens">
<!-- <ng-template #toolbar>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #layout> <!-- <ov-toolbar toolbar (onCamClicked)="onCamClicked()"></ov-toolbar> -->
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #panel> <!-- <ov-toolbar panel (onCamClicked)="onCamClicked()"></ov-toolbar> -->
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar> <!-- <ov-toolbar chatPanel (onCamClicked)="onCamClicked()"></ov-toolbar> -->
</ng-template> --> <!-- <ov-toolbar participantsPanel (onCamClicked)="onCamClicked()"></ov-toolbar> -->
<!-- <ng-template #chatPanel>
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #participantsPanel> <!-- <ov-toolbar layout (onCamClicked)="onCamClicked()"></ov-toolbar> -->
<ov-toolbar postion="top" (onCamClicked)="onCamClicked()"></ov-toolbar>
</ng-template> -->
<!-- <ng-template #stream let-stream="stream"> <!-- <div *ovStream="let stream">
<ov-stream postion="top" [stream]="stream">
<button network-quality> hola</button>
<ng-template #notification>
<button mat-icon-button id="hand-notification" *ngIf="stream.videoEnlarged">
<mat-icon>front_hand</mat-icon>
</button>
</ng-template>
</ov-stream>
</ng-template> -->
<p>{{stream.videoEnlarged}}</p>
<ov-stream [stream]="stream"></ov-stream>
</div> -->
</ov-videoconference> </ov-videoconference>

View File

@ -1,13 +1,14 @@
import { Component, OnInit } from '@angular/core'; import { Component, ContentChild, OnInit } from '@angular/core';
import { RestService } from '../services/rest.service'; import { RestService } from '../services/rest.service';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-call', selector: 'app-call',
templateUrl: './call.component.html', templateUrl: './call.component.html',
styleUrls: ['./call.component.scss'] styleUrls: ['./call.component.scss']
}) })
export class CallComponent implements OnInit { export class CallComponent implements OnInit {
sessionId = 'prueba-majestuosa-amable'; sessionId = 'prueba-majestuosa-amable';
tokens: { webcam: string; screen: string }; tokens: { webcam: string; screen: string };