diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/panel.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/panel.component.ts index 31729ff4..8462165d 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/panel.component.ts @@ -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(); 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 */ diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participant-panel-item/participant-panel-item.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participant-panel-item/participant-panel-item.component.ts index 33bb1113..5d4ebe5e 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participant-panel-item/participant-panel-item.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/panel/participants-panel/participant-panel-item/participant-panel-item.component.ts @@ -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; 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 eee00a69..3fe03b02 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 @@ -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 */ diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.ts index 7a39f46a..31be3917 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/session/session.component.ts @@ -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(); @@ -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); diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts index af83b00a..417da154 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts @@ -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(); 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 */ 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 0ea78379..87e97752 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 @@ -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; + /** + * @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; } } 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 new file mode 100644 index 00000000..c10f8e83 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/services/template/template-manager.service.ts @@ -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; + toolbarAdditionalButtonsTemplate?: TemplateRef; + toolbarAdditionalPanelButtonsTemplate?: TemplateRef; + + // Panel templates + panelTemplate: TemplateRef; + chatPanelTemplate: TemplateRef; + participantsPanelTemplate: TemplateRef; + activitiesPanelTemplate: TemplateRef; + additionalPanelsTemplate?: TemplateRef; + + // Participant templates + participantPanelItemTemplate: TemplateRef; + participantPanelItemElementsTemplate?: TemplateRef; + + // Layout templates + layoutTemplate: TemplateRef; + streamTemplate: TemplateRef; + + // PreJoin template + preJoinTemplate?: TemplateRef; +} + +/** + * Configuration object for panel component templates + */ +export interface PanelTemplateConfiguration { + participantsPanelTemplate?: TemplateRef; + chatPanelTemplate?: TemplateRef; + activitiesPanelTemplate?: TemplateRef; + additionalPanelsTemplate?: TemplateRef; + backgroundEffectsPanelTemplate?: TemplateRef; + settingsPanelTemplate?: TemplateRef; +} + +/** + * Configuration object for toolbar component templates + */ +export interface ToolbarTemplateConfiguration { + toolbarAdditionalButtonsTemplate?: TemplateRef; + toolbarAdditionalPanelButtonsTemplate?: TemplateRef; +} + +/** + * Configuration object for participants panel component templates + */ +export interface ParticipantsPanelTemplateConfiguration { + participantPanelItemTemplate?: TemplateRef; +} + +/** + * Configuration object for participant panel item component templates + */ +export interface ParticipantPanelItemTemplateConfiguration { + participantPanelItemElementsTemplate?: TemplateRef; +} + +/** + * Configuration object for session component templates + */ +export interface SessionTemplateConfiguration { + toolbarTemplate?: TemplateRef; + panelTemplate?: TemplateRef; + layoutTemplate?: TemplateRef; +} + +/** + * 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; + panel: TemplateRef; + chatPanel: TemplateRef; + participantsPanel: TemplateRef; + activitiesPanel: TemplateRef; + participantPanelItem: TemplateRef; + layout: TemplateRef; + stream: TemplateRef; +} + +/** + * 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 { + 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 { + 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 { + 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 | 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 { + 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 { + 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 { + 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 { + 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 { + 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 + ): 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, + panelTemplate?: TemplateRef, + layoutTemplate?: TemplateRef + ): SessionTemplateConfiguration { + this.log.d('Setting up session templates...'); + + return { + toolbarTemplate, + panelTemplate, + layoutTemplate + }; + } +}