ov-components: Implement centralized template management for videoconference components

master
Carlos Santos 2025-07-22 19:24:07 +02:00
parent 04b8b741e2
commit 22af5c7df6
7 changed files with 709 additions and 196 deletions

View File

@ -25,6 +25,7 @@ import {
} from '../../models/panel.model';
import { PanelService } from '../../services/panel/panel.service';
import { BackgroundEffect } from '../../models/background-effect.model';
import { TemplateManagerService, PanelTemplateConfiguration } from '../../services/template/template-manager.service';
/**
*
@ -75,42 +76,20 @@ export class PanelComponent implements OnInit {
*/
@ContentChild(ParticipantsPanelDirective)
set externalParticipantPanel(externalParticipantsPanel: ParticipantsPanelDirective) {
// This directive will has value only when PARTICIPANTS PANEL component tagged with '*ovParticipantsPanel'
// is inside of the PANEL component tagged with '*ovPanel'
this._externalParticipantPanel = externalParticipantsPanel;
if (externalParticipantsPanel) {
this.participantsPanelTemplate = externalParticipantsPanel.template;
this.updateTemplatesAndMarkForCheck();
}
}
// TODO: backgroundEffectsPanel does not provides customization
// @ContentChild(BackgroundEffectsPanelDirective)
// set externalBackgroundEffectsPanel(externalBackgroundEffectsPanel: BackgroundEffectsPanelDirective) {
// This directive will has value only when BACKGROUND EFFECTS PANEL component tagged with '*ovBackgroundEffectsPanel'
// is inside of the PANEL component tagged with '*ovPanel'
// if (externalBackgroundEffectsPanel) {
// this.backgroundEffectsPanelTemplate = externalBackgroundEffectsPanel.template;
// }
// }
// TODO: settingsPanel does not provides customization
// @ContentChild(SettingsPanelDirective)
// set externalSettingsPanel(externalSettingsPanel: SettingsPanelDirective) {
// This directive will has value only when SETTINGS PANEL component tagged with '*ovSettingsPanel'
// is inside of the PANEL component tagged with '*ovPanel'
// if (externalSettingsPanel) {
// this.settingsPanelTemplate = externalSettingsPanel.template;
// }
// }
/**
* @ignore
*/
@ContentChild(ActivitiesPanelDirective)
set externalActivitiesPanel(externalActivitiesPanel: ActivitiesPanelDirective) {
// This directive will has value only when ACTIVITIES PANEL component tagged with '*ovActivitiesPanel'
// is inside of the PANEL component tagged with '*ovPanel'
this._externalActivitiesPanel = externalActivitiesPanel;
if (externalActivitiesPanel) {
this.activitiesPanelTemplate = externalActivitiesPanel.template;
this.updateTemplatesAndMarkForCheck();
}
}
@ -119,10 +98,9 @@ export class PanelComponent implements OnInit {
*/
@ContentChild(ChatPanelDirective)
set externalChatPanel(externalChatPanel: ChatPanelDirective) {
// This directive will has value only when CHAT PANEL component tagged with '*ovChatPanel'
// is inside of the PANEL component tagged with '*ovPanel'
this._externalChatPanel = externalChatPanel;
if (externalChatPanel) {
this.chatPanelTemplate = externalChatPanel.template;
this.updateTemplatesAndMarkForCheck();
}
}
@ -131,10 +109,9 @@ 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'
this._externalAdditionalPanels = externalAdditionalPanels;
if (externalAdditionalPanels) {
this.additionalPanelsTemplate = externalAdditionalPanels.template;
this.updateTemplatesAndMarkForCheck();
}
}
@ -195,6 +172,19 @@ export class PanelComponent implements OnInit {
* @internal
*/
isExternalPanelOpened: boolean;
/**
* @internal
* Template configuration managed by the service
*/
templateConfig: PanelTemplateConfiguration = {};
// Store directive references for template setup
private _externalParticipantPanel?: ParticipantsPanelDirective;
private _externalChatPanel?: ChatPanelDirective;
private _externalActivitiesPanel?: ActivitiesPanelDirective;
private _externalAdditionalPanels?: AdditionalPanelsDirective;
private destroy$ = new Subject<void>();
private panelEmitersHandler: Map<
@ -207,19 +197,66 @@ export class PanelComponent implements OnInit {
*/
constructor(
private panelService: PanelService,
private cd: ChangeDetectorRef
private cd: ChangeDetectorRef,
private templateManagerService: TemplateManagerService
) {}
/**
* @ignore
*/
ngOnInit(): void {
this.setupTemplates();
this.subscribeToPanelToggling();
this.panelEmitersHandler.set(PanelType.CHAT, this.onChatPanelStatusChanged);
this.panelEmitersHandler.set(PanelType.PARTICIPANTS, this.onParticipantsPanelStatusChanged);
this.panelEmitersHandler.set(PanelType.SETTINGS, this.onSettingsPanelStatusChanged);
this.panelEmitersHandler.set(PanelType.ACTIVITIES, this.onActivitiesPanelStatusChanged);
}
/**
* @internal
* Sets up all templates using the template manager service
*/
private setupTemplates(): void {
this.templateConfig = this.templateManagerService.setupPanelTemplates(
this._externalParticipantPanel,
this._externalChatPanel,
this._externalActivitiesPanel,
this._externalAdditionalPanels
);
// Apply templates to component properties for backward compatibility
this.applyTemplateConfiguration();
}
/**
* @internal
* Applies the template configuration to component properties
*/
private applyTemplateConfiguration(): void {
if (this.templateConfig.participantsPanelTemplate) {
this.participantsPanelTemplate = this.templateConfig.participantsPanelTemplate;
}
if (this.templateConfig.chatPanelTemplate) {
this.chatPanelTemplate = this.templateConfig.chatPanelTemplate;
}
if (this.templateConfig.activitiesPanelTemplate) {
this.activitiesPanelTemplate = this.templateConfig.activitiesPanelTemplate;
}
if (this.templateConfig.additionalPanelsTemplate) {
this.additionalPanelsTemplate = this.templateConfig.additionalPanelsTemplate;
}
}
/**
* @internal
* Updates templates and triggers change detection
*/
private updateTemplatesAndMarkForCheck(): void {
this.setupTemplates();
this.cd.markForCheck();
}
/**
* @ignore
*/

View File

@ -4,6 +4,7 @@ import { ParticipantPanelItemElementsDirective } from '../../../../directives/te
import { ParticipantModel } from '../../../../models/participant.model';
import { OpenViduComponentsConfigService } from '../../../../services/config/directive-config.service';
import { ParticipantService } from '../../../../services/participant/participant.service';
import { TemplateManagerService, ParticipantPanelItemTemplateConfiguration } from '../../../../services/template/template-manager.service';
/**
*
@ -35,13 +36,21 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
*/
@ContentChild(ParticipantPanelItemElementsDirective)
set externalItemElements(externalItemElements: ParticipantPanelItemElementsDirective) {
// This directive will has value only when ITEM ELEMENTS component tagget with '*ovParticipantPanelItemElements' directive
// is inside of the P PANEL ITEM component tagged with '*ovParticipantPanelItem' directive
this._externalItemElements = externalItemElements;
if (externalItemElements) {
this.participantPanelItemElementsTemplate = externalItemElements.template;
this.updateTemplatesAndMarkForCheck();
}
}
/**
* @internal
* Template configuration managed by the service
*/
templateConfig: ParticipantPanelItemTemplateConfiguration = {};
// Store directive references for template setup
private _externalItemElements?: ParticipantPanelItemElementsDirective;
/**
* The participant to be displayed
* @ignore
@ -62,13 +71,15 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
constructor(
private libService: OpenViduComponentsConfigService,
private participantService: ParticipantService,
private cd: ChangeDetectorRef
private cd: ChangeDetectorRef,
private templateManagerService: TemplateManagerService
) {}
/**
* @ignore
*/
ngOnInit(): void {
this.setupTemplates();
this.subscribeToParticipantPanelItemDirectives();
}
@ -88,6 +99,38 @@ export class ParticipantPanelItemComponent implements OnInit, OnDestroy {
}
}
/**
* @internal
* Sets up all templates using the template manager service
*/
private setupTemplates(): void {
this.templateConfig = this.templateManagerService.setupParticipantPanelItemTemplates(
this._externalItemElements
);
// Apply templates to component properties for backward compatibility
this.applyTemplateConfiguration();
}
/**
* @internal
* Applies the template configuration to component properties
*/
private applyTemplateConfiguration(): void {
if (this.templateConfig.participantPanelItemElementsTemplate) {
this.participantPanelItemElementsTemplate = this.templateConfig.participantPanelItemElementsTemplate;
}
}
/**
* @internal
* Updates templates and triggers change detection
*/
private updateTemplatesAndMarkForCheck(): void {
this.setupTemplates();
this.cd.markForCheck();
}
private subscribeToParticipantPanelItemDirectives() {
this.muteButtonSub = this.libService.participantItemMuteButton$.subscribe((value: boolean) => {
this.showMuteButton = value;

View File

@ -15,6 +15,7 @@ import { PanelService } from '../../../../services/panel/panel.service';
import { ParticipantPanelItemDirective } from '../../../../directives/template/openvidu-components-angular.directive';
import { Subscription } from 'rxjs';
import { ParticipantModel } from '../../../../models/participant.model';
import { TemplateManagerService, ParticipantsPanelTemplateConfiguration } from '../../../../services/template/template-manager.service';
/**
* The **ParticipantsPanelComponent** is hosted inside of the {@link PanelComponent}.
@ -53,13 +54,21 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI
*/
@ContentChild(ParticipantPanelItemDirective)
set externalParticipantPanelItem(externalParticipantPanelItem: ParticipantPanelItemDirective) {
// This directive will has value only when PARTICIPANT PANEL ITEM component tagged with '*ovParticipantPanelItem'
// is inside of the PARTICIPANTS PANEL component tagged with '*ovParticipantsPanel'
this._externalParticipantPanelItem = externalParticipantPanelItem;
if (externalParticipantPanelItem) {
this.participantPanelItemTemplate = externalParticipantPanelItem.template;
this.updateTemplatesAndMarkForCheck();
}
}
/**
* @internal
* Template configuration managed by the service
*/
templateConfig: ParticipantsPanelTemplateConfiguration = {};
// Store directive references for template setup
private _externalParticipantPanelItem?: ParticipantPanelItemDirective;
private localParticipantSubs: Subscription;
private remoteParticipantsSubs: Subscription;
@ -69,13 +78,16 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI
constructor(
private participantService: ParticipantService,
private panelService: PanelService,
private cd: ChangeDetectorRef
private cd: ChangeDetectorRef,
private templateManagerService: TemplateManagerService
) {}
/**
* @ignore
*/
ngOnInit(): void {
this.setupTemplates();
this.localParticipantSubs = this.participantService.localParticipant$.subscribe((p: ParticipantModel | undefined) => {
if (p) {
this.localParticipant = p;
@ -109,6 +121,39 @@ export class ParticipantsPanelComponent implements OnInit, OnDestroy, AfterViewI
}
}
/**
* @internal
* Sets up all templates using the template manager service
*/
private setupTemplates(): void {
this.templateConfig = this.templateManagerService.setupParticipantsPanelTemplates(
this._externalParticipantPanelItem,
this.defaultParticipantPanelItemTemplate
);
// Apply templates to component properties for backward compatibility
this.applyTemplateConfiguration();
}
/**
* @internal
* Applies the template configuration to component properties
*/
private applyTemplateConfiguration(): void {
if (this.templateConfig.participantPanelItemTemplate) {
this.participantPanelItemTemplate = this.templateConfig.participantPanelItemTemplate;
}
}
/**
* @internal
* Updates templates and triggers change detection
*/
private updateTemplatesAndMarkForCheck(): void {
this.setupTemplates();
this.cd.markForCheck();
}
/**
* @ignore
*/

View File

@ -48,6 +48,7 @@ import {
} from 'livekit-client';
import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model';
import { RecordingStatus } from '../../models/recording.model';
import { TemplateManagerService, SessionTemplateConfiguration } from '../../services/template/template-manager.service';
/**
* @internal
@ -103,6 +104,12 @@ export class SessionComponent implements OnInit, OnDestroy {
drawer: MatDrawerContainer;
loading: boolean = true;
/**
* @internal
* Template configuration managed by the service
*/
templateConfig: SessionTemplateConfiguration = {};
private shouldDisconnectRoomWhenComponentIsDestroyed: boolean = true;
private readonly SIDENAV_WIDTH_LIMIT_MODE = 790;
private destroy$ = new Subject<void>();
@ -123,9 +130,11 @@ export class SessionComponent implements OnInit, OnDestroy {
private translateService: TranslateService,
// private captionService: CaptionService,
private backgroundService: VirtualBackgroundService,
private cd: ChangeDetectorRef
private cd: ChangeDetectorRef,
private templateManagerService: TemplateManagerService
) {
this.log = this.loggerSrv.get('SessionComponent');
this.setupTemplates();
}
@HostListener('window:beforeunload')
@ -251,6 +260,18 @@ export class SessionComponent implements OnInit, OnDestroy {
});
}
/**
* @internal
* Sets up all templates using the template manager service
*/
private setupTemplates(): void {
this.templateConfig = this.templateManagerService.setupSessionTemplates(
this.toolbarTemplate,
this.panelTemplate,
this.layoutTemplate
);
}
async ngOnDestroy() {
if (this.shouldDisconnectRoomWhenComponentIsDestroyed) {
await this.disconnectRoom(ParticipantLeftReason.LEAVE);

View File

@ -44,6 +44,7 @@ import { ParticipantService } from '../../services/participant/participant.servi
import { PlatformService } from '../../services/platform/platform.service';
import { RecordingService } from '../../services/recording/recording.service';
import { StorageService } from '../../services/storage/storage.service';
import { TemplateManagerService, ToolbarTemplateConfiguration } from '../../services/template/template-manager.service';
import { TranslateService } from '../../services/translate/translate.service';
import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service';
import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model';
@ -77,10 +78,9 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
*/
@ContentChild(ToolbarAdditionalButtonsDirective)
set externalAdditionalButtons(externalAdditionalButtons: ToolbarAdditionalButtonsDirective) {
// This directive will has value only when ADDITIONAL BUTTONS component (tagged with '*ovToolbarAdditionalButtons' directive)
// is inside of the TOOLBAR component tagged with '*ovToolbar' directive
this._externalAdditionalButtons = externalAdditionalButtons;
if (externalAdditionalButtons) {
this.toolbarAdditionalButtonsTemplate = externalAdditionalButtons.template;
this.updateTemplatesAndMarkForCheck();
}
}
@ -89,10 +89,9 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
*/
@ContentChild(ToolbarAdditionalPanelButtonsDirective)
set externalAdditionalPanelButtons(externalAdditionalPanelButtons: ToolbarAdditionalPanelButtonsDirective) {
// This directive will has value only when ADDITIONAL PANEL BUTTONS component tagged with '*ovToolbarAdditionalPanelButtons' directive
// is inside of the TOOLBAR component tagged with '*ovToolbar' directive
this._externalAdditionalPanelButtons = externalAdditionalPanelButtons;
if (externalAdditionalPanelButtons) {
this.toolbarAdditionalPanelButtonsTemplate = externalAdditionalPanelButtons.template;
this.updateTemplatesAndMarkForCheck();
}
}
@ -355,6 +354,16 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
*/
recordingTime: Date;
/**
* @internal
* Template configuration managed by the service
*/
templateConfig: ToolbarTemplateConfiguration = {};
// Store directive references for template setup
private _externalAdditionalButtons?: ToolbarAdditionalButtonsDirective;
private _externalAdditionalPanelButtons?: ToolbarAdditionalPanelButtonsDirective;
private log: ILogger;
private destroy$ = new Subject<void>();
private currentWindowHeight = window.innerHeight;
@ -379,7 +388,8 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
private broadcastingService: BroadcastingService,
private translateService: TranslateService,
private storageSrv: StorageService,
private cdkOverlayService: CdkOverlayService
private cdkOverlayService: CdkOverlayService,
private templateManagerService: TemplateManagerService
) {
this.log = this.loggerSrv.get('ToolbarComponent');
}
@ -413,6 +423,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
this.hasVideoDevices = this.oVDevicesService.hasVideoDeviceAvailable();
this.hasAudioDevices = this.oVDevicesService.hasAudioDeviceAvailable();
this.setupTemplates();
this.subscribeToToolbarDirectives();
this.subscribeToUserMediaProperties();
@ -436,6 +447,42 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
this.cdkOverlayService.setSelector('body');
}
/**
* @internal
* Sets up all templates using the template manager service
*/
private setupTemplates(): void {
this.templateConfig = this.templateManagerService.setupToolbarTemplates(
this._externalAdditionalButtons,
this._externalAdditionalPanelButtons
);
// Apply templates to component properties for backward compatibility
this.applyTemplateConfiguration();
}
/**
* @internal
* Applies the template configuration to component properties
*/
private applyTemplateConfiguration(): void {
if (this.templateConfig.toolbarAdditionalButtonsTemplate) {
this.toolbarAdditionalButtonsTemplate = this.templateConfig.toolbarAdditionalButtonsTemplate;
}
if (this.templateConfig.toolbarAdditionalPanelButtonsTemplate) {
this.toolbarAdditionalPanelButtonsTemplate = this.templateConfig.toolbarAdditionalPanelButtonsTemplate;
}
}
/**
* @internal
* Updates templates and triggers change detection
*/
private updateTemplatesAndMarkForCheck(): void {
this.setupTemplates();
this.cd.markForCheck();
}
/**
* @internal
*/

View File

@ -1,5 +1,5 @@
import { animate, style, transition, trigger } from '@angular/animations';
import { AfterViewInit, Component, ContentChild, EventEmitter, OnDestroy, Output, TemplateRef, ViewChild } from '@angular/core';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, EventEmitter, OnDestroy, Output, TemplateRef, ViewChild } from '@angular/core';
import { Subject, filter, skip, take, takeUntil } from 'rxjs';
import {
ActivitiesPanelDirective,
@ -24,6 +24,7 @@ import { DeviceService } from '../../services/device/device.service';
import { LoggerService } from '../../services/logger/logger.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { StorageService } from '../../services/storage/storage.service';
import { TemplateManagerService, TemplateConfiguration, ExternalDirectives, DefaultTemplates } from '../../services/template/template-manager.service';
import { Room } from 'livekit-client';
import { ParticipantLeftEvent, ParticipantModel } from '../../models/participant.model';
import { CustomDevice } from '../../models/device.model';
@ -218,6 +219,12 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
*/
openviduAngularPreJoinTemplate: TemplateRef<any>;
/**
* @internal
* Template configuration managed by TemplateManagerService
*/
private templateConfig: TemplateConfiguration;
/**
* Provides event notifications that fire when the local participant is ready to join to the room.
* This event emits the participant name as data.
@ -445,7 +452,8 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
private deviceSrv: DeviceService,
private openviduService: OpenViduService,
private actionService: ActionService,
private libService: OpenViduComponentsConfigService
private libService: OpenViduComponentsConfigService,
private templateManagerService: TemplateManagerService
) {
this.log = this.loggerSrv.get('VideoconferenceComponent');
@ -499,161 +507,69 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
* @internal
*/
private setupTemplates(): void {
this.setupToolbarTemplate();
this.setupPanelTemplate();
this.setupLayoutTemplate();
this.setupPreJoinTemplate();
const externalDirectives: ExternalDirectives = {
toolbar: this.externalToolbar,
toolbarAdditionalButtons: this.externalToolbarAdditionalButtons,
toolbarAdditionalPanelButtons: this.externalToolbarAdditionalPanelButtons,
additionalPanels: this.externalAdditionalPanels,
panel: this.externalPanel,
chatPanel: this.externalChatPanel,
activitiesPanel: this.externalActivitiesPanel,
participantsPanel: this.externalParticipantsPanel,
participantPanelItem: this.externalParticipantPanelItem,
participantPanelItemElements: this.externalParticipantPanelItemElements,
layout: this.externalLayout,
stream: this.externalStream,
preJoin: this.externalPreJoin
};
const defaultTemplates: DefaultTemplates = {
toolbar: this.defaultToolbarTemplate,
panel: this.defaultPanelTemplate,
chatPanel: this.defaultChatPanelTemplate,
participantsPanel: this.defaultParticipantsPanelTemplate,
activitiesPanel: this.defaultActivitiesPanelTemplate,
participantPanelItem: this.defaultParticipantPanelItemTemplate,
layout: this.defaultLayoutTemplate,
stream: this.defaultStreamTemplate
};
// Use the template manager service to set up all templates
this.templateConfig = this.templateManagerService.setupTemplates(externalDirectives, defaultTemplates);
// Apply the configuration to the component properties
this.applyTemplateConfiguration();
}
/**
* @internal
* Applies the template configuration to component properties
*/
private setupToolbarTemplate(): void {
if (this.externalToolbar) {
this.log.d('Setting EXTERNAL TOOLBAR');
this.openviduAngularToolbarTemplate = this.externalToolbar.template;
} else {
this.log.d('Setting DEFAULT TOOLBAR');
this.setupToolbarAdditionalButtons();
this.openviduAngularToolbarTemplate = this.defaultToolbarTemplate;
}
}
private applyTemplateConfiguration(): void {
this.openviduAngularToolbarTemplate = this.templateConfig.toolbarTemplate;
this.openviduAngularPanelTemplate = this.templateConfig.panelTemplate;
this.openviduAngularChatPanelTemplate = this.templateConfig.chatPanelTemplate;
this.openviduAngularParticipantsPanelTemplate = this.templateConfig.participantsPanelTemplate;
this.openviduAngularActivitiesPanelTemplate = this.templateConfig.activitiesPanelTemplate;
this.openviduAngularParticipantPanelItemTemplate = this.templateConfig.participantPanelItemTemplate;
this.openviduAngularLayoutTemplate = this.templateConfig.layoutTemplate;
this.openviduAngularStreamTemplate = this.templateConfig.streamTemplate;
/**
* @internal
*/
private setupToolbarAdditionalButtons(): void {
if (this.externalToolbarAdditionalButtons) {
this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL BUTTONS');
this.openviduAngularToolbarAdditionalButtonsTemplate = this.externalToolbarAdditionalButtons.template;
// Optional templates
if (this.templateConfig.toolbarAdditionalButtonsTemplate) {
this.openviduAngularToolbarAdditionalButtonsTemplate = this.templateConfig.toolbarAdditionalButtonsTemplate;
}
if (this.externalToolbarAdditionalPanelButtons) {
this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL PANEL BUTTONS');
this.openviduAngularToolbarAdditionalPanelButtonsTemplate = this.externalToolbarAdditionalPanelButtons.template;
if (this.templateConfig.toolbarAdditionalPanelButtonsTemplate) {
this.openviduAngularToolbarAdditionalPanelButtonsTemplate = this.templateConfig.toolbarAdditionalPanelButtonsTemplate;
}
}
/**
* @internal
*/
private setupPanelTemplate(): void {
if (this.externalPanel) {
this.log.d('Setting EXTERNAL PANEL');
this.openviduAngularPanelTemplate = this.externalPanel.template;
} else {
this.log.d('Setting DEFAULT PANEL');
this.setupParticipantsPanel();
this.setupChatPanel();
this.setupActivitiesPanel();
this.setupAdditionalPanels();
this.openviduAngularPanelTemplate = this.defaultPanelTemplate;
if (this.templateConfig.additionalPanelsTemplate) {
this.openviduAngularAdditionalPanelsTemplate = this.templateConfig.additionalPanelsTemplate;
}
}
/**
* @internal
*/
private setupParticipantsPanel(): void {
if (this.externalParticipantsPanel) {
this.openviduAngularParticipantsPanelTemplate = this.externalParticipantsPanel.template;
this.log.d('Setting EXTERNAL PARTICIPANTS PANEL');
} else {
this.log.d('Setting DEFAULT PARTICIPANTS PANEL');
this.setupParticipantPanelItem();
this.openviduAngularParticipantsPanelTemplate = this.defaultParticipantsPanelTemplate;
if (this.templateConfig.participantPanelItemElementsTemplate) {
this.openviduAngularParticipantPanelItemElementsTemplate = this.templateConfig.participantPanelItemElementsTemplate;
}
}
/**
* @internal
*/
private setupParticipantPanelItem(): void {
if (this.externalParticipantPanelItem) {
this.log.d('Setting EXTERNAL P ITEM');
this.openviduAngularParticipantPanelItemTemplate = this.externalParticipantPanelItem.template;
} else {
if (this.externalParticipantPanelItemElements) {
this.log.d('Setting EXTERNAL PARTICIPANT PANEL ITEM ELEMENT');
this.openviduAngularParticipantPanelItemElementsTemplate = this.externalParticipantPanelItemElements.template;
}
this.openviduAngularParticipantPanelItemTemplate = this.defaultParticipantPanelItemTemplate;
this.log.d('Setting DEFAULT P ITEM');
}
}
/**
* @internal
*/
private setupChatPanel(): void {
if (this.externalChatPanel) {
this.log.d('Setting EXTERNAL CHAT PANEL');
this.openviduAngularChatPanelTemplate = this.externalChatPanel.template;
} else {
this.log.d('Setting DEFAULT CHAT PANEL');
this.openviduAngularChatPanelTemplate = this.defaultChatPanelTemplate;
}
}
/**
* @internal
*/
private setupActivitiesPanel(): void {
if (this.externalActivitiesPanel) {
this.log.d('Setting EXTERNAL ACTIVITIES PANEL');
this.openviduAngularActivitiesPanelTemplate = this.externalActivitiesPanel.template;
} else {
this.log.d('Setting DEFAULT ACTIVITIES PANEL');
this.openviduAngularActivitiesPanelTemplate = this.defaultActivitiesPanelTemplate;
}
}
/**
* @internal
*/
private setupAdditionalPanels(): void {
if (this.externalAdditionalPanels) {
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
this.openviduAngularAdditionalPanelsTemplate = this.externalAdditionalPanels.template;
}
}
/**
* @internal
*/
private setupLayoutTemplate(): void {
if (this.externalLayout) {
this.log.d('Setting EXTERNAL LAYOUT');
this.openviduAngularLayoutTemplate = this.externalLayout.template;
} else {
this.log.d('Setting DEFAULT LAYOUT');
this.setupStreamTemplate();
this.openviduAngularLayoutTemplate = this.defaultLayoutTemplate;
}
}
/**
* @internal
*/
private setupStreamTemplate(): void {
if (this.externalStream) {
this.log.d('Setting EXTERNAL STREAM');
this.openviduAngularStreamTemplate = this.externalStream.template;
} else {
this.log.d('Setting DEFAULT STREAM');
this.openviduAngularStreamTemplate = this.defaultStreamTemplate;
}
}
/**
* @internal
*/
private setupPreJoinTemplate(): void {
if (this.externalPreJoin) {
this.log.d('Setting EXTERNAL PREJOIN');
this.openviduAngularPreJoinTemplate = this.externalPreJoin.template;
} else {
this.log.d('Setting DEFAULT PREJOIN');
// Keep the default behavior - no template is set
if (this.templateConfig.preJoinTemplate) {
this.openviduAngularPreJoinTemplate = this.templateConfig.preJoinTemplate;
}
}

View File

@ -0,0 +1,404 @@
import { Injectable, TemplateRef } from '@angular/core';
import { ILogger } from '../../models/logger.model';
import { LoggerService } from '../logger/logger.service';
import {
ActivitiesPanelDirective,
AdditionalPanelsDirective,
ChatPanelDirective,
LayoutDirective,
PanelDirective,
ParticipantPanelItemDirective,
ParticipantPanelItemElementsDirective,
ParticipantsPanelDirective,
PreJoinDirective,
StreamDirective,
ToolbarAdditionalButtonsDirective,
ToolbarAdditionalPanelButtonsDirective,
ToolbarDirective
} from '../../directives/template/openvidu-components-angular.directive';
/**
* Configuration object for all templates in the videoconference component
*/
export interface TemplateConfiguration {
// Toolbar templates
toolbarTemplate: TemplateRef<any>;
toolbarAdditionalButtonsTemplate?: TemplateRef<any>;
toolbarAdditionalPanelButtonsTemplate?: TemplateRef<any>;
// Panel templates
panelTemplate: TemplateRef<any>;
chatPanelTemplate: TemplateRef<any>;
participantsPanelTemplate: TemplateRef<any>;
activitiesPanelTemplate: TemplateRef<any>;
additionalPanelsTemplate?: TemplateRef<any>;
// Participant templates
participantPanelItemTemplate: TemplateRef<any>;
participantPanelItemElementsTemplate?: TemplateRef<any>;
// Layout templates
layoutTemplate: TemplateRef<any>;
streamTemplate: TemplateRef<any>;
// PreJoin template
preJoinTemplate?: TemplateRef<any>;
}
/**
* Configuration object for panel component templates
*/
export interface PanelTemplateConfiguration {
participantsPanelTemplate?: TemplateRef<any>;
chatPanelTemplate?: TemplateRef<any>;
activitiesPanelTemplate?: TemplateRef<any>;
additionalPanelsTemplate?: TemplateRef<any>;
backgroundEffectsPanelTemplate?: TemplateRef<any>;
settingsPanelTemplate?: TemplateRef<any>;
}
/**
* Configuration object for toolbar component templates
*/
export interface ToolbarTemplateConfiguration {
toolbarAdditionalButtonsTemplate?: TemplateRef<any>;
toolbarAdditionalPanelButtonsTemplate?: TemplateRef<any>;
}
/**
* Configuration object for participants panel component templates
*/
export interface ParticipantsPanelTemplateConfiguration {
participantPanelItemTemplate?: TemplateRef<any>;
}
/**
* Configuration object for participant panel item component templates
*/
export interface ParticipantPanelItemTemplateConfiguration {
participantPanelItemElementsTemplate?: TemplateRef<any>;
}
/**
* Configuration object for session component templates
*/
export interface SessionTemplateConfiguration {
toolbarTemplate?: TemplateRef<any>;
panelTemplate?: TemplateRef<any>;
layoutTemplate?: TemplateRef<any>;
}
/**
* External directives provided by the consumer
*/
export interface ExternalDirectives {
toolbar?: ToolbarDirective;
toolbarAdditionalButtons?: ToolbarAdditionalButtonsDirective;
toolbarAdditionalPanelButtons?: ToolbarAdditionalPanelButtonsDirective;
additionalPanels?: AdditionalPanelsDirective;
panel?: PanelDirective;
chatPanel?: ChatPanelDirective;
activitiesPanel?: ActivitiesPanelDirective;
participantsPanel?: ParticipantsPanelDirective;
participantPanelItem?: ParticipantPanelItemDirective;
participantPanelItemElements?: ParticipantPanelItemElementsDirective;
layout?: LayoutDirective;
stream?: StreamDirective;
preJoin?: PreJoinDirective;
}
/**
* Default templates provided by the component
*/
export interface DefaultTemplates {
toolbar: TemplateRef<any>;
panel: TemplateRef<any>;
chatPanel: TemplateRef<any>;
participantsPanel: TemplateRef<any>;
activitiesPanel: TemplateRef<any>;
participantPanelItem: TemplateRef<any>;
layout: TemplateRef<any>;
stream: TemplateRef<any>;
}
/**
* Service responsible for managing and configuring templates for the videoconference component.
* This service centralizes all template setup logic, making the main component cleaner and more maintainable.
*/
@Injectable({
providedIn: 'root'
})
export class TemplateManagerService {
private log: ILogger;
constructor(private loggerSrv: LoggerService) {
this.log = this.loggerSrv.get('TemplateManagerService');
}
/**
* Sets up all templates based on external directives and default templates
*/
setupTemplates(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateConfiguration {
this.log.d('Setting up templates...');
const config: TemplateConfiguration = {
toolbarTemplate: this.setupToolbarTemplate(externalDirectives, defaultTemplates),
panelTemplate: this.setupPanelTemplate(externalDirectives, defaultTemplates),
layoutTemplate: this.setupLayoutTemplate(externalDirectives, defaultTemplates),
preJoinTemplate: this.setupPreJoinTemplate(externalDirectives),
// Individual templates
chatPanelTemplate: this.setupChatPanelTemplate(externalDirectives, defaultTemplates),
participantsPanelTemplate: this.setupParticipantsPanelTemplate(externalDirectives, defaultTemplates),
activitiesPanelTemplate: this.setupActivitiesPanelTemplate(externalDirectives, defaultTemplates),
participantPanelItemTemplate: this.setupParticipantPanelItemTemplate(externalDirectives, defaultTemplates),
streamTemplate: this.setupStreamTemplate(externalDirectives, defaultTemplates)
};
// Optional templates
if (externalDirectives.toolbarAdditionalButtons) {
config.toolbarAdditionalButtonsTemplate = externalDirectives.toolbarAdditionalButtons.template;
this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL BUTTONS');
}
if (externalDirectives.toolbarAdditionalPanelButtons) {
config.toolbarAdditionalPanelButtonsTemplate = externalDirectives.toolbarAdditionalPanelButtons.template;
this.log.d('Setting EXTERNAL TOOLBAR ADDITIONAL PANEL BUTTONS');
}
if (externalDirectives.additionalPanels) {
config.additionalPanelsTemplate = externalDirectives.additionalPanels.template;
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
}
if (externalDirectives.participantPanelItemElements) {
config.participantPanelItemElementsTemplate = externalDirectives.participantPanelItemElements.template;
this.log.d('Setting EXTERNAL PARTICIPANT PANEL ITEM ELEMENTS');
}
this.log.d('Template setup completed', config);
return config;
}
/**
* Sets up the toolbar template
*/
private setupToolbarTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.toolbar) {
this.log.d('Setting EXTERNAL TOOLBAR');
return externalDirectives.toolbar.template;
} else {
this.log.d('Setting DEFAULT TOOLBAR');
return defaultTemplates.toolbar;
}
}
/**
* Sets up the panel template
*/
private setupPanelTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.panel) {
this.log.d('Setting EXTERNAL PANEL');
return externalDirectives.panel.template;
} else {
this.log.d('Setting DEFAULT PANEL');
return defaultTemplates.panel;
}
}
/**
* Sets up the layout template
*/
private setupLayoutTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.layout) {
this.log.d('Setting EXTERNAL LAYOUT');
return externalDirectives.layout.template;
} else {
this.log.d('Setting DEFAULT LAYOUT');
return defaultTemplates.layout;
}
}
/**
* Sets up the prejoin template
*/
private setupPreJoinTemplate(externalDirectives: ExternalDirectives): TemplateRef<any> | undefined {
if (externalDirectives.preJoin) {
this.log.d('Setting EXTERNAL PREJOIN');
return externalDirectives.preJoin.template;
} else {
this.log.d('Setting DEFAULT PREJOIN (none)');
return undefined;
}
}
/**
* Sets up the chat panel template
*/
private setupChatPanelTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.chatPanel) {
this.log.d('Setting EXTERNAL CHAT PANEL');
return externalDirectives.chatPanel.template;
} else {
this.log.d('Setting DEFAULT CHAT PANEL');
return defaultTemplates.chatPanel;
}
}
/**
* Sets up the participants panel template
*/
private setupParticipantsPanelTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.participantsPanel) {
this.log.d('Setting EXTERNAL PARTICIPANTS PANEL');
return externalDirectives.participantsPanel.template;
} else {
this.log.d('Setting DEFAULT PARTICIPANTS PANEL');
return defaultTemplates.participantsPanel;
}
}
/**
* Sets up the activities panel template
*/
private setupActivitiesPanelTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.activitiesPanel) {
this.log.d('Setting EXTERNAL ACTIVITIES PANEL');
return externalDirectives.activitiesPanel.template;
} else {
this.log.d('Setting DEFAULT ACTIVITIES PANEL');
return defaultTemplates.activitiesPanel;
}
}
/**
* Sets up the participant panel item template
*/
private setupParticipantPanelItemTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.participantPanelItem) {
this.log.d('Setting EXTERNAL PARTICIPANT PANEL ITEM');
return externalDirectives.participantPanelItem.template;
} else {
this.log.d('Setting DEFAULT PARTICIPANT PANEL ITEM');
return defaultTemplates.participantPanelItem;
}
}
/**
* Sets up the stream template
*/
private setupStreamTemplate(
externalDirectives: ExternalDirectives,
defaultTemplates: DefaultTemplates
): TemplateRef<any> {
if (externalDirectives.stream) {
this.log.d('Setting EXTERNAL STREAM');
return externalDirectives.stream.template;
} else {
this.log.d('Setting DEFAULT STREAM');
return defaultTemplates.stream;
}
}
/**
* Sets up templates for the PanelComponent
*/
setupPanelTemplates(
externalParticipantsPanel?: ParticipantsPanelDirective,
externalChatPanel?: ChatPanelDirective,
externalActivitiesPanel?: ActivitiesPanelDirective,
externalAdditionalPanels?: AdditionalPanelsDirective
): PanelTemplateConfiguration {
this.log.d('Setting up panel templates...');
return {
participantsPanelTemplate: externalParticipantsPanel?.template,
chatPanelTemplate: externalChatPanel?.template,
activitiesPanelTemplate: externalActivitiesPanel?.template,
additionalPanelsTemplate: externalAdditionalPanels?.template
};
}
/**
* Sets up templates for the ToolbarComponent
*/
setupToolbarTemplates(
externalAdditionalButtons?: ToolbarAdditionalButtonsDirective,
externalAdditionalPanelButtons?: ToolbarAdditionalPanelButtonsDirective
): ToolbarTemplateConfiguration {
this.log.d('Setting up toolbar templates...');
return {
toolbarAdditionalButtonsTemplate: externalAdditionalButtons?.template,
toolbarAdditionalPanelButtonsTemplate: externalAdditionalPanelButtons?.template
};
}
/**
* Sets up templates for the ParticipantsPanelComponent
*/
setupParticipantsPanelTemplates(
externalParticipantPanelItem?: ParticipantPanelItemDirective,
defaultParticipantPanelItem?: TemplateRef<any>
): ParticipantsPanelTemplateConfiguration {
this.log.d('Setting up participants panel templates...');
return {
participantPanelItemTemplate: externalParticipantPanelItem?.template || defaultParticipantPanelItem
};
}
/**
* Sets up templates for the ParticipantPanelItemComponent
*/
setupParticipantPanelItemTemplates(
externalParticipantPanelItemElements?: ParticipantPanelItemElementsDirective
): ParticipantPanelItemTemplateConfiguration {
this.log.d('Setting up participant panel item templates...');
return {
participantPanelItemElementsTemplate: externalParticipantPanelItemElements?.template
};
}
/**
* Sets up templates for the SessionComponent
*/
setupSessionTemplates(
toolbarTemplate?: TemplateRef<any>,
panelTemplate?: TemplateRef<any>,
layoutTemplate?: TemplateRef<any>
): SessionTemplateConfiguration {
this.log.d('Setting up session templates...');
return {
toolbarTemplate,
panelTemplate,
layoutTemplate
};
}
}