From e9ecceeb7773689d063ecd6d28a1e92c4738d7ec Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Wed, 30 Jul 2025 19:37:40 +0200 Subject: [PATCH] ov-components: Add participant panel directive for enhanced user experience --- .../participants-panel.component.html | 3 +- .../participants-panel.component.ts | 49 ++-- .../videoconference.component.html | 9 +- .../videoconference.component.ts | 15 +- .../lib/directives/api/internals.directive.ts | 2 +- .../template/internals.directive.ts | 224 ++++++++++++++++++ ...idu-components-angular.directive.module.ts | 6 +- .../openvidu-components-angular.directive.ts | 193 --------------- .../template/template-manager.service.ts | 65 +++-- .../src/public-api.ts | 1 + 10 files changed, 314 insertions(+), 253 deletions(-) create mode 100644 openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/internals.directive.ts diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.html index dbc39a7d..fb3e9aa1 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.html +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.html @@ -7,14 +7,13 @@
-
+
-
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.ts index 3fe03b02..7b9e00ff 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participants-panel/participants-panel.component.ts @@ -13,9 +13,10 @@ import { import { ParticipantService } from '../../../../services/participant/participant.service'; import { PanelService } from '../../../../services/panel/panel.service'; import { ParticipantPanelItemDirective } from '../../../../directives/template/openvidu-components-angular.directive'; -import { Subscription } from 'rxjs'; +import { Subject, takeUntil } from 'rxjs'; import { ParticipantModel } from '../../../../models/participant.model'; import { TemplateManagerService, ParticipantsPanelTemplateConfiguration } from '../../../../services/template/template-manager.service'; +import { OpenViduComponentsConfigService } from '../../../../services/config/directive-config.service'; /** * The **ParticipantsPanelComponent** is hosted inside of the {@link PanelComponent}. @@ -49,6 +50,12 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI */ @ContentChild('participantPanelItem', { read: TemplateRef }) participantPanelItemTemplate: TemplateRef; + /** + * @ignore + */ + @ContentChild('participantPanelAfterLocalParticipant', { read: TemplateRef }) + participantPanelAfterLocalParticipantTemplate: TemplateRef; + /** * @ignore */ @@ -69,8 +76,7 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI // Store directive references for template setup private _externalParticipantPanelItem?: ParticipantPanelItemDirective; - private localParticipantSubs: Subscription; - private remoteParticipantsSubs: Subscription; + private destroy$ = new Subject(); /** * @ignore @@ -79,7 +85,8 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI private participantService: ParticipantService, private panelService: PanelService, private cd: ChangeDetectorRef, - private templateManagerService: TemplateManagerService + private templateManagerService: TemplateManagerService, + private libService: OpenViduComponentsConfigService ) {} /** @@ -88,25 +95,15 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI ngOnInit(): void { this.setupTemplates(); - this.localParticipantSubs = this.participantService.localParticipant$.subscribe((p: ParticipantModel | undefined) => { - if (p) { - this.localParticipant = p; - this.cd.markForCheck(); - } - }); - - this.remoteParticipantsSubs = this.participantService.remoteParticipants$.subscribe((p: ParticipantModel[]) => { - this.remoteParticipants = p; - this.cd.markForCheck(); - }); + this.subscribeToParticipantsChanges(); } /** * @ignore */ ngOnDestroy() { - if (this.localParticipantSubs) this.localParticipantSubs.unsubscribe(); - if (this.remoteParticipantsSubs) this.remoteParticipantsSubs.unsubscribe; + this.destroy$.next(); + this.destroy$.complete(); } /** @@ -121,6 +118,21 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI } } + private subscribeToParticipantsChanges() { + this.participantService.localParticipant$.pipe(takeUntil(this.destroy$)).subscribe((p: ParticipantModel | undefined) => { + if (p) { + this.localParticipant = p; + this.cd.markForCheck(); + } + }); + + this.participantService.remoteParticipants$.pipe(takeUntil(this.destroy$)).subscribe((p: ParticipantModel[]) => { + this.remoteParticipants = p; + this.cd.markForCheck(); + }); + } + + /** * @internal * Sets up all templates using the template manager service @@ -143,6 +155,9 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI if (this.templateConfig.participantPanelItemTemplate) { this.participantPanelItemTemplate = this.templateConfig.participantPanelItemTemplate; } + if (this.templateConfig.participantPanelAfterLocalParticipantTemplate) { + this.participantPanelAfterLocalParticipantTemplate = this.templateConfig.participantPanelAfterLocalParticipantTemplate; + } } /** diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html index e98f47cb..0a2f1787 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.html @@ -26,7 +26,11 @@ {{ componentState.error?.message }}
-
+
+ + + diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts index 2270a537..ab9cc6ce 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/videoconference/videoconference.component.ts @@ -10,7 +10,6 @@ import { ParticipantPanelItemDirective, ParticipantPanelItemElementsDirective, ParticipantsPanelDirective, - PreJoinDirective, StreamDirective, ToolbarAdditionalButtonsDirective, ToolbarAdditionalPanelButtonsDirective, @@ -43,6 +42,7 @@ import { } from '../../models/recording.model'; import { BroadcastingStartRequestedEvent, BroadcastingStopRequestedEvent } from '../../models/broadcasting.model'; import { LangOption } from '../../models/lang.model'; +import { ParticipantPanelAfterLocalParticipantDirective, PreJoinDirective } from '../../directives/template/internals.directive'; /** * The **VideoconferenceComponent** is the parent of all OpenVidu components. @@ -129,6 +129,11 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { * @internal */ @ContentChild(PreJoinDirective) externalPreJoin: PreJoinDirective; + /** + * @internal + * + */ + @ContentChild(ParticipantPanelAfterLocalParticipantDirective) externalParticipantPanelAfterLocalParticipant: ParticipantPanelAfterLocalParticipantDirective; /** * @internal @@ -198,6 +203,10 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { * @internal */ openviduAngularAdditionalPanelsTemplate: TemplateRef; + /** + * @internal + */ + openviduAngularParticipantPanelAfterLocalParticipantTemplate: TemplateRef; /** * @internal */ @@ -516,6 +525,7 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { chatPanel: this.externalChatPanel, activitiesPanel: this.externalActivitiesPanel, participantsPanel: this.externalParticipantsPanel, + participantPanelAfterLocalParticipant: this.externalParticipantPanelAfterLocalParticipant, participantPanelItem: this.externalParticipantPanelItem, participantPanelItemElements: this.externalParticipantPanelItemElements, layout: this.externalLayout, @@ -565,6 +575,9 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit { if (this.templateConfig.additionalPanelsTemplate) { this.openviduAngularAdditionalPanelsTemplate = this.templateConfig.additionalPanelsTemplate; } + if (this.templateConfig.participantPanelAfterLocalParticipantTemplate) { + this.openviduAngularParticipantPanelAfterLocalParticipantTemplate = this.templateConfig.participantPanelAfterLocalParticipantTemplate; + } if (this.templateConfig.participantPanelItemElementsTemplate) { this.openviduAngularParticipantPanelItemElementsTemplate = this.templateConfig.participantPanelItemElementsTemplate; } diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/api/internals.directive.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/api/internals.directive.ts index b108a5a6..5a5d6257 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/api/internals.directive.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/api/internals.directive.ts @@ -473,4 +473,4 @@ export class RecordingActivityShowRecordingsListDirective implements AfterViewIn private update(value: boolean) { this.libService.updateRecordingActivityConfig({ showRecordingsList: value }); } -} +} \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/internals.directive.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/internals.directive.ts new file mode 100644 index 00000000..44eb5589 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/internals.directive.ts @@ -0,0 +1,224 @@ +/** + * The ***ovPreJoin** directive empowers you to substitute the default pre-join component template with a custom one. + * This directive allows you to create a completely custom pre-join experience while maintaining the core functionality. + * + * In the example below, we demonstrate how to replace the pre-join template with a custom one that includes + * device selection and a custom join button. + * + * + * ```typescript + * import { HttpClient } from '@angular/common/http'; + * import { Component } from '@angular/core'; + * import { lastValueFrom } from 'rxjs'; + * import { FormsModule } from '@angular/forms'; + * + * import { + * DeviceService, + * ParticipantService, + * OpenViduComponentsModule, + * } from 'openvidu-components-angular'; + * + * @Component({ + * selector: 'app-root', + * template: ` + * + * + *
+ *

Join Meeting

+ *
+ * + * + *
+ *
+ *
+ * `, + * styles: ` + * .custom-prejoin { + * display: flex; + * flex-direction: column; + * align-items: center; + * justify-content: center; + * height: 100vh; + * background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + * color: white; + * } + * .prejoin-form { + * display: flex; + * flex-direction: column; + * gap: 20px; + * align-items: center; + * } + * .name-input { + * padding: 12px; + * border: none; + * border-radius: 8px; + * font-size: 16px; + * min-width: 250px; + * } + * .join-button { + * padding: 12px 24px; + * background: #4CAF50; + * color: white; + * border: none; + * border-radius: 8px; + * font-size: 16px; + * cursor: pointer; + * transition: background 0.3s; + * } + * .join-button:hover:not(:disabled) { + * background: #45a049; + * } + * .join-button:disabled { + * background: #cccccc; + * cursor: not-allowed; + * } + * `, + * standalone: true, + * imports: [OpenViduComponentsModule, FormsModule], + * }) + * export class AppComponent { + * // For local development, leave these variables empty + * // For production, configure them with correct URLs depending on your deployment + * APPLICATION_SERVER_URL = ''; + * LIVEKIT_URL = ''; + * + * // Define the name of the room and initialize the token variable + * roomName = 'custom-prejoin'; + * token!: string; + * participantName: string = ''; + * + * constructor( + * private httpClient: HttpClient, + * private deviceService: DeviceService, + * private participantService: ParticipantService + * ) { + * this.configureUrls(); + * } + * + * private configureUrls() { + * // If APPLICATION_SERVER_URL is not configured, use default value from local development + * if (!this.APPLICATION_SERVER_URL) { + * if (window.location.hostname === 'localhost') { + * this.APPLICATION_SERVER_URL = 'http://localhost:6080/'; + * } else { + * this.APPLICATION_SERVER_URL = + * 'https://' + window.location.hostname + ':6443/'; + * } + * } + * + * // If LIVEKIT_URL is not configured, use default value from local development + * if (!this.LIVEKIT_URL) { + * if (window.location.hostname === 'localhost') { + * this.LIVEKIT_URL = 'ws://localhost:7880/'; + * } else { + * this.LIVEKIT_URL = 'wss://' + window.location.hostname + ':7443/'; + * } + * } + * } + * + * // Function to request a token when a participant joins the room + * async onTokenRequested(participantName: string) { + * const { token } = await this.getToken(this.roomName, participantName); + * this.token = token; + * } + * + * // Function called when ready to join + * onReadyToJoin() { + * console.log('Ready to join the meeting'); + * } + * + * // Function to join the meeting + * async joinMeeting() { + * if (this.participantName.trim()) { + * // Request token with the participant name + * await this.onTokenRequested(this.participantName); + * } + * } + * + * // Function to get a token from the server + * getToken(roomName: string, participantName: string): Promise { + * try { + * // Send a POST request to the server to obtain a token + * return lastValueFrom( + * this.httpClient.post(this.APPLICATION_SERVER_URL + 'token', { + * roomName, + * participantName, + * }) + * ); + * } catch (error: any) { + * // Handle errors, e.g., if the server is not reachable + * if (error.status === 404) { + * throw { + * status: error.status, + * message: + * 'Cannot connect with the backend. ' + error.url + ' not found', + * }; + * } + * throw error; + * } + * } + * } + * + * ``` + * + * + * For a detailed tutorial on customizing the pre-join component, please visit [this link](https://openvidu.io/latest/docs/tutorials/angular-components/openvidu-custom-prejoin/). + */ + +import { Directive, TemplateRef, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[ovPreJoin]', + standalone: false +}) +export class PreJoinDirective { + constructor( + public template: TemplateRef, + public container: ViewContainerRef + ) {} +} + + +/** + * The **ovParticipantPanelAfterLocalParticipant** directive allows you to inject custom HTML or Angular templates + * immediately after the local participant item in the participant panel. + * This enables you to extend the participant panel with additional controls, information, or UI elements. + * + * Usage example: + * ```html + * + * + *
+ * + * Custom content after local participant + *
+ *
+ *
+ * ``` + */ +@Directive({ + selector: '[ovParticipantPanelAfterLocalParticipant]', + standalone: false +}) +export class ParticipantPanelAfterLocalParticipantDirective { + constructor( + public template: TemplateRef, + public container: ViewContainerRef + ) {} +} \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts index 793f923d..6442345e 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.module.ts @@ -12,9 +12,9 @@ import { ToolbarAdditionalPanelButtonsDirective, AdditionalPanelsDirective, ActivitiesPanelDirective, - BackgroundEffectsPanelDirective, - PreJoinDirective + BackgroundEffectsPanelDirective } from './openvidu-components-angular.directive'; +import { ParticipantPanelAfterLocalParticipantDirective, PreJoinDirective } from './internals.directive'; @NgModule({ declarations: [ @@ -31,6 +31,7 @@ import { ParticipantPanelItemElementsDirective, ActivitiesPanelDirective, PreJoinDirective, + ParticipantPanelAfterLocalParticipantDirective // BackgroundEffectsPanelDirective ], exports: [ @@ -47,6 +48,7 @@ import { ParticipantPanelItemElementsDirective, ActivitiesPanelDirective, PreJoinDirective, + ParticipantPanelAfterLocalParticipantDirective // BackgroundEffectsPanelDirective ] }) diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts index 13bef658..806ff35e 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/directives/template/openvidu-components-angular.directive.ts @@ -1815,196 +1815,3 @@ export class StreamDirective { ) {} } -/** - * The ***ovPreJoin** directive empowers you to substitute the default pre-join component template with a custom one. - * This directive allows you to create a completely custom pre-join experience while maintaining the core functionality. - * - * In the example below, we demonstrate how to replace the pre-join template with a custom one that includes - * device selection and a custom join button. - * - * - * ```typescript - * import { HttpClient } from '@angular/common/http'; - * import { Component } from '@angular/core'; - * import { lastValueFrom } from 'rxjs'; - * import { FormsModule } from '@angular/forms'; - * - * import { - * DeviceService, - * ParticipantService, - * OpenViduComponentsModule, - * } from 'openvidu-components-angular'; - * - * @Component({ - * selector: 'app-root', - * template: ` - * - * - *
- *

Join Meeting

- *
- * - * - *
- *
- *
- * `, - * styles: ` - * .custom-prejoin { - * display: flex; - * flex-direction: column; - * align-items: center; - * justify-content: center; - * height: 100vh; - * background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - * color: white; - * } - * .prejoin-form { - * display: flex; - * flex-direction: column; - * gap: 20px; - * align-items: center; - * } - * .name-input { - * padding: 12px; - * border: none; - * border-radius: 8px; - * font-size: 16px; - * min-width: 250px; - * } - * .join-button { - * padding: 12px 24px; - * background: #4CAF50; - * color: white; - * border: none; - * border-radius: 8px; - * font-size: 16px; - * cursor: pointer; - * transition: background 0.3s; - * } - * .join-button:hover:not(:disabled) { - * background: #45a049; - * } - * .join-button:disabled { - * background: #cccccc; - * cursor: not-allowed; - * } - * `, - * standalone: true, - * imports: [OpenViduComponentsModule, FormsModule], - * }) - * export class AppComponent { - * // For local development, leave these variables empty - * // For production, configure them with correct URLs depending on your deployment - * APPLICATION_SERVER_URL = ''; - * LIVEKIT_URL = ''; - * - * // Define the name of the room and initialize the token variable - * roomName = 'custom-prejoin'; - * token!: string; - * participantName: string = ''; - * - * constructor( - * private httpClient: HttpClient, - * private deviceService: DeviceService, - * private participantService: ParticipantService - * ) { - * this.configureUrls(); - * } - * - * private configureUrls() { - * // If APPLICATION_SERVER_URL is not configured, use default value from local development - * if (!this.APPLICATION_SERVER_URL) { - * if (window.location.hostname === 'localhost') { - * this.APPLICATION_SERVER_URL = 'http://localhost:6080/'; - * } else { - * this.APPLICATION_SERVER_URL = - * 'https://' + window.location.hostname + ':6443/'; - * } - * } - * - * // If LIVEKIT_URL is not configured, use default value from local development - * if (!this.LIVEKIT_URL) { - * if (window.location.hostname === 'localhost') { - * this.LIVEKIT_URL = 'ws://localhost:7880/'; - * } else { - * this.LIVEKIT_URL = 'wss://' + window.location.hostname + ':7443/'; - * } - * } - * } - * - * // Function to request a token when a participant joins the room - * async onTokenRequested(participantName: string) { - * const { token } = await this.getToken(this.roomName, participantName); - * this.token = token; - * } - * - * // Function called when ready to join - * onReadyToJoin() { - * console.log('Ready to join the meeting'); - * } - * - * // Function to join the meeting - * async joinMeeting() { - * if (this.participantName.trim()) { - * // Request token with the participant name - * await this.onTokenRequested(this.participantName); - * } - * } - * - * // Function to get a token from the server - * getToken(roomName: string, participantName: string): Promise { - * try { - * // Send a POST request to the server to obtain a token - * return lastValueFrom( - * this.httpClient.post(this.APPLICATION_SERVER_URL + 'token', { - * roomName, - * participantName, - * }) - * ); - * } catch (error: any) { - * // Handle errors, e.g., if the server is not reachable - * if (error.status === 404) { - * throw { - * status: error.status, - * message: - * 'Cannot connect with the backend. ' + error.url + ' not found', - * }; - * } - * throw error; - * } - * } - * } - * - * ``` - * - * - * For a detailed tutorial on customizing the pre-join component, please visit [this link](https://openvidu.io/latest/docs/tutorials/angular-components/openvidu-custom-prejoin/). - */ - -@Directive({ - selector: '[ovPreJoin]', - standalone: false -}) -export class PreJoinDirective { - constructor( - public template: TemplateRef, - public container: ViewContainerRef - ) {} -} diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/template/template-manager.service.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/template/template-manager.service.ts index c10f8e83..794fb9a1 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/template/template-manager.service.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/template/template-manager.service.ts @@ -10,12 +10,12 @@ import { ParticipantPanelItemDirective, ParticipantPanelItemElementsDirective, ParticipantsPanelDirective, - PreJoinDirective, StreamDirective, ToolbarAdditionalButtonsDirective, ToolbarAdditionalPanelButtonsDirective, ToolbarDirective } from '../../directives/template/openvidu-components-angular.directive'; +import { PreJoinDirective, ParticipantPanelAfterLocalParticipantDirective } from '../../directives/template/internals.directive'; /** * Configuration object for all templates in the videoconference component @@ -34,6 +34,7 @@ export interface TemplateConfiguration { additionalPanelsTemplate?: TemplateRef; // Participant templates + participantPanelAfterLocalParticipantTemplate?: TemplateRef; participantPanelItemTemplate: TemplateRef; participantPanelItemElementsTemplate?: TemplateRef; @@ -70,6 +71,7 @@ export interface ToolbarTemplateConfiguration { */ export interface ParticipantsPanelTemplateConfiguration { participantPanelItemTemplate?: TemplateRef; + participantPanelAfterLocalParticipantTemplate?: TemplateRef; } /** @@ -100,6 +102,7 @@ export interface ExternalDirectives { chatPanel?: ChatPanelDirective; activitiesPanel?: ActivitiesPanelDirective; participantsPanel?: ParticipantsPanelDirective; + participantPanelAfterLocalParticipant?: ParticipantPanelAfterLocalParticipantDirective; participantPanelItem?: ParticipantPanelItemDirective; participantPanelItemElements?: ParticipantPanelItemElementsDirective; layout?: LayoutDirective; @@ -138,10 +141,7 @@ export class TemplateManagerService { /** * Sets up all templates based on external directives and default templates */ - setupTemplates( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateConfiguration { + setupTemplates(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateConfiguration { this.log.d('Setting up templates...'); const config: TemplateConfiguration = { @@ -155,7 +155,8 @@ export class TemplateManagerService { participantsPanelTemplate: this.setupParticipantsPanelTemplate(externalDirectives, defaultTemplates), activitiesPanelTemplate: this.setupActivitiesPanelTemplate(externalDirectives, defaultTemplates), participantPanelItemTemplate: this.setupParticipantPanelItemTemplate(externalDirectives, defaultTemplates), - streamTemplate: this.setupStreamTemplate(externalDirectives, defaultTemplates) + streamTemplate: this.setupStreamTemplate(externalDirectives, defaultTemplates), + participantPanelAfterLocalParticipantTemplate: this.setupParticipantPanelAfterLocalParticipantTemplate(externalDirectives) }; // Optional templates @@ -183,13 +184,21 @@ export class TemplateManagerService { return config; } + /** + * Sets up the participantPanelAfterLocalParticipant template + */ + private setupParticipantPanelAfterLocalParticipantTemplate(externalDirectives: ExternalDirectives): TemplateRef | undefined { + if (externalDirectives.participantPanelAfterLocalParticipant) { + this.log.d('Setting EXTERNAL PARTICIPANT PANEL AFTER LOCAL PARTICIPANT'); + return (externalDirectives.participantPanelAfterLocalParticipant as any).template; + } + return undefined; + } + /** * Sets up the toolbar template */ - private setupToolbarTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupToolbarTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.toolbar) { this.log.d('Setting EXTERNAL TOOLBAR'); return externalDirectives.toolbar.template; @@ -202,10 +211,7 @@ export class TemplateManagerService { /** * Sets up the panel template */ - private setupPanelTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupPanelTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.panel) { this.log.d('Setting EXTERNAL PANEL'); return externalDirectives.panel.template; @@ -218,10 +224,7 @@ export class TemplateManagerService { /** * Sets up the layout template */ - private setupLayoutTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupLayoutTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.layout) { this.log.d('Setting EXTERNAL LAYOUT'); return externalDirectives.layout.template; @@ -247,10 +250,7 @@ export class TemplateManagerService { /** * Sets up the chat panel template */ - private setupChatPanelTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupChatPanelTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.chatPanel) { this.log.d('Setting EXTERNAL CHAT PANEL'); return externalDirectives.chatPanel.template; @@ -263,10 +263,7 @@ export class TemplateManagerService { /** * Sets up the participants panel template */ - private setupParticipantsPanelTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupParticipantsPanelTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.participantsPanel) { this.log.d('Setting EXTERNAL PARTICIPANTS PANEL'); return externalDirectives.participantsPanel.template; @@ -279,10 +276,7 @@ export class TemplateManagerService { /** * Sets up the activities panel template */ - private setupActivitiesPanelTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupActivitiesPanelTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.activitiesPanel) { this.log.d('Setting EXTERNAL ACTIVITIES PANEL'); return externalDirectives.activitiesPanel.template; @@ -311,10 +305,7 @@ export class TemplateManagerService { /** * Sets up the stream template */ - private setupStreamTemplate( - externalDirectives: ExternalDirectives, - defaultTemplates: DefaultTemplates - ): TemplateRef { + private setupStreamTemplate(externalDirectives: ExternalDirectives, defaultTemplates: DefaultTemplates): TemplateRef { if (externalDirectives.stream) { this.log.d('Setting EXTERNAL STREAM'); return externalDirectives.stream.template; @@ -363,12 +354,14 @@ export class TemplateManagerService { */ setupParticipantsPanelTemplates( externalParticipantPanelItem?: ParticipantPanelItemDirective, - defaultParticipantPanelItem?: TemplateRef + defaultParticipantPanelItem?: TemplateRef, + externalParticipantPanelAfterLocalParticipant?: TemplateRef ): ParticipantsPanelTemplateConfiguration { this.log.d('Setting up participants panel templates...'); return { - participantPanelItemTemplate: externalParticipantPanelItem?.template || defaultParticipantPanelItem + participantPanelItemTemplate: externalParticipantPanelItem?.template || defaultParticipantPanelItem, + participantPanelAfterLocalParticipantTemplate: externalParticipantPanelAfterLocalParticipant }; } diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts index 0cb29885..8d74796e 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts @@ -18,6 +18,7 @@ export * from './lib/components/toolbar/toolbar.component'; export * from './lib/components/videoconference/videoconference.component'; export * from './lib/config/openvidu-components-angular.config'; // Directives +export * from './lib/directives/template/internals.directive'; export * from './lib/directives/api/activities-panel.directive'; export * from './lib/directives/api/admin.directive'; export * from './lib/directives/api/api.directive.module';