ov-components: Refactored and improved config

pull/842/head
Carlos Santos 2024-09-04 12:19:13 +02:00
parent 724fbd9186
commit bd6ba55504
15 changed files with 199 additions and 71 deletions

View File

@ -11,7 +11,7 @@ import {
ViewChild, ViewChild,
ViewContainerRef ViewContainerRef
} from '@angular/core'; } from '@angular/core';
import { Subscription } from 'rxjs'; import { combineLatest, map, Subscription } from 'rxjs';
import { StreamDirective } from '../../directives/template/openvidu-components-angular.directive'; import { StreamDirective } from '../../directives/template/openvidu-components-angular.directive';
import { ParticipantTrackPublication, ParticipantModel } from '../../models/participant.model'; import { ParticipantTrackPublication, ParticipantModel } from '../../models/participant.model';
import { LayoutService } from '../../services/layout/layout.service'; import { LayoutService } from '../../services/layout/layout.service';
@ -19,6 +19,8 @@ import { ParticipantService } from '../../services/participant/participant.servi
import { CdkDrag } from '@angular/cdk/drag-drop'; import { CdkDrag } from '@angular/cdk/drag-drop';
import { PanelService } from '../../services/panel/panel.service'; import { PanelService } from '../../services/panel/panel.service';
import { GlobalConfigService } from '../../services/config/global-config.service'; import { GlobalConfigService } from '../../services/config/global-config.service';
import { ServiceConfigService } from '../../services/config/service-config.service';
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
/** /**
* *
@ -78,17 +80,21 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
private resizeTimeout: NodeJS.Timeout; private resizeTimeout: NodeJS.Timeout;
private videoIsAtRight: boolean = false; private videoIsAtRight: boolean = false;
private lastLayoutWidth: number = 0; private lastLayoutWidth: number = 0;
private layoutService: LayoutService;
/** /**
* @ignore * @ignore
*/ */
constructor( constructor(
private layoutService: LayoutService, private serviceConfig: ServiceConfigService,
private panelService: PanelService, private panelService: PanelService,
private participantService: ParticipantService, private participantService: ParticipantService,
private globalService: GlobalConfigService, private globalService: GlobalConfigService,
private directiveService: OpenViduComponentsConfigService,
private cd: ChangeDetectorRef private cd: ChangeDetectorRef
) {} ) {
this.layoutService = this.serviceConfig.getLayoutService();
}
ngOnInit(): void { ngOnInit(): void {
this.subscribeToParticipants(); this.subscribeToParticipants();
@ -96,6 +102,7 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
} }
ngAfterViewInit() { ngAfterViewInit() {
console.log('LayoutComponent.ngAfterViewInit');
this.layoutService.initialize(this.layoutContainer.element.nativeElement); this.layoutService.initialize(this.layoutContainer.element.nativeElement);
this.lastLayoutWidth = this.layoutContainer.element.nativeElement.getBoundingClientRect().width; this.lastLayoutWidth = this.layoutContainer.element.nativeElement.getBoundingClientRect().width;
this.listenToResizeLayout(); this.listenToResizeLayout();
@ -142,11 +149,20 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
} }
}); });
this.remoteParticipantsSubs = this.participantService.remoteParticipants$.subscribe((participants) => { this.remoteParticipantsSubs = combineLatest([
this.participantService.remoteParticipants$,
this.directiveService.layoutRemoteParticipants$
])
.pipe(
map(([serviceParticipants, directiveParticipants]) =>
directiveParticipants !== undefined ? directiveParticipants : serviceParticipants
)
)
.subscribe((participants) => {
this.remoteParticipants = participants; this.remoteParticipants = participants;
this.layoutService.update(); this.layoutService.update();
this.cd.markForCheck(); this.cd.markForCheck();
}); });
} }
private listenToResizeLayout() { private listenToResizeLayout() {

View File

@ -3,7 +3,6 @@ import { Subscription } from 'rxjs';
import { ILogger } from '../../models/logger.model'; import { ILogger } from '../../models/logger.model';
import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service'; import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service';
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service'; import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
import { LayoutService } from '../../services/layout/layout.service';
import { LoggerService } from '../../services/logger/logger.service'; import { LoggerService } from '../../services/logger/logger.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service'; import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { TranslateService } from '../../services/translate/translate.service'; import { TranslateService } from '../../services/translate/translate.service';
@ -55,11 +54,9 @@ export class PreJoinComponent implements OnInit, OnDestroy {
@HostListener('window:resize') @HostListener('window:resize')
sizeChange() { sizeChange() {
this.windowSize = window.innerWidth; this.windowSize = window.innerWidth;
this.layoutService.update();
} }
constructor( constructor(
private layoutService: LayoutService,
private loggerSrv: LoggerService, private loggerSrv: LoggerService,
private libService: OpenViduComponentsConfigService, private libService: OpenViduComponentsConfigService,
private cdkSrv: CdkOverlayService, private cdkSrv: CdkOverlayService,

View File

@ -47,6 +47,7 @@ import {
Track Track
} from 'livekit-client'; } from 'livekit-client';
import { ParticipantModel } from '../../models/participant.model'; import { ParticipantModel } from '../../models/participant.model';
import { ServiceConfigService } from '../../services/config/service-config.service';
/** /**
* @internal * @internal
@ -88,15 +89,16 @@ export class SessionComponent implements OnInit, OnDestroy {
private updateLayoutInterval: NodeJS.Timeout; private updateLayoutInterval: NodeJS.Timeout;
private captionLanguageSubscription: Subscription; private captionLanguageSubscription: Subscription;
private log: ILogger; private log: ILogger;
private layoutService: LayoutService;
constructor( constructor(
private serviceConfig: ServiceConfigService,
private actionService: ActionService, private actionService: ActionService,
private openviduService: OpenViduService, private openviduService: OpenViduService,
private participantService: ParticipantService, private participantService: ParticipantService,
private loggerSrv: LoggerService, private loggerSrv: LoggerService,
private chatService: ChatService, private chatService: ChatService,
private libService: OpenViduComponentsConfigService, private libService: OpenViduComponentsConfigService,
private layoutService: LayoutService,
private panelService: PanelService, private panelService: PanelService,
private recordingService: RecordingService, private recordingService: RecordingService,
private broadcastingService: BroadcastingService, private broadcastingService: BroadcastingService,
@ -106,6 +108,7 @@ export class SessionComponent implements OnInit, OnDestroy {
private cd: ChangeDetectorRef private cd: ChangeDetectorRef
) { ) {
this.log = this.loggerSrv.get('SessionComponent'); this.log = this.loggerSrv.get('SessionComponent');
this.layoutService = this.serviceConfig.getLayoutService();
} }
@HostListener('window:beforeunload') @HostListener('window:beforeunload')
@ -205,7 +208,7 @@ export class SessionComponent implements OnInit, OnDestroy {
} }
async ngOnDestroy() { async ngOnDestroy() {
if(this.shouldDisconnectRoomWhenComponentIsDestroyed) { if (this.shouldDisconnectRoomWhenComponentIsDestroyed) {
await this.disconnectRoom(); await this.disconnectRoom();
} }
this.room.removeAllListeners(); this.room.removeAllListeners();

View File

@ -4,6 +4,7 @@ import { CaptionsLangOption } from '../../../models/caption.model';
import { CaptionService } from '../../../services/caption/caption.service'; import { CaptionService } from '../../../services/caption/caption.service';
import { LayoutService } from '../../../services/layout/layout.service'; import { LayoutService } from '../../../services/layout/layout.service';
import { OpenViduService } from '../../../services/openvidu/openvidu.service'; import { OpenViduService } from '../../../services/openvidu/openvidu.service';
import { ServiceConfigService } from '../../../services/config/service-config.service';
/** /**
* @internal * @internal
@ -22,8 +23,11 @@ export class CaptionsSettingComponent implements OnInit, OnDestroy {
private captionsStatusSubs: Subscription; private captionsStatusSubs: Subscription;
private sttStatusSubs: Subscription; private sttStatusSubs: Subscription;
private layoutService: LayoutService;
constructor(private layoutService: LayoutService, private captionService: CaptionService, private openviduService: OpenViduService) {} constructor(private serviceConfig: ServiceConfigService, private captionService: CaptionService, private openviduService: OpenViduService) {
this.layoutService = this.serviceConfig.getLayoutService();
}
ngOnInit(): void { ngOnInit(): void {
// this.isOpenViduPro = this.openviduService.isOpenViduPro(); // this.isOpenViduPro = this.openviduService.isOpenViduPro();

View File

@ -4,11 +4,10 @@ import { Subscription } from 'rxjs';
import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service'; import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service';
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service'; import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
import { LayoutService } from '../../services/layout/layout.service'; import { LayoutService } from '../../services/layout/layout.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
import { StorageService } from '../../services/storage/storage.service';
import { Track } from 'livekit-client'; import { Track } from 'livekit-client';
import { ParticipantTrackPublication } from '../../models/participant.model'; import { ParticipantTrackPublication } from '../../models/participant.model';
import { ServiceConfigService } from '../../services/config/service-config.service';
/** /**
* The **StreamComponent** is hosted inside of the {@link LayoutComponent}. * The **StreamComponent** is hosted inside of the {@link LayoutComponent}.
@ -99,17 +98,18 @@ export class StreamComponent implements OnInit, OnDestroy {
private videoControlsSub: Subscription; private videoControlsSub: Subscription;
private readonly HOVER_TIMEOUT = 3000; private readonly HOVER_TIMEOUT = 3000;
private layoutService: LayoutService;
/** /**
* @ignore * @ignore
*/ */
constructor( constructor(
private openviduService: OpenViduService, private serviceConfig: ServiceConfigService,
private layoutService: LayoutService,
private participantService: ParticipantService, private participantService: ParticipantService,
private storageService: StorageService,
private cdkSrv: CdkOverlayService, private cdkSrv: CdkOverlayService,
private libService: OpenViduComponentsConfigService private libService: OpenViduComponentsConfigService
) {} ) {
this.layoutService = this.serviceConfig.getLayoutService();
}
ngOnInit() { ngOnInit() {
this.subscribeToStreamDirectives(); this.subscribeToStreamDirectives();

View File

@ -49,6 +49,7 @@ import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.servic
import { ParticipantModel } from '../../models/participant.model'; import { ParticipantModel } from '../../models/participant.model';
import { Room, RoomEvent } from 'livekit-client'; import { Room, RoomEvent } from 'livekit-client';
import { ToolbarAdditionalButtonsPosition } from '../../models/toolbar.model'; import { ToolbarAdditionalButtonsPosition } from '../../models/toolbar.model';
import { ServiceConfigService } from '../../services/config/service-config.service';
/** /**
* The **ToolbarComponent** is hosted inside of the {@link VideoconferenceComponent}. * The **ToolbarComponent** is hosted inside of the {@link VideoconferenceComponent}.
@ -342,11 +343,13 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
private additionalButtonsPositionSub: Subscription; private additionalButtonsPositionSub: Subscription;
private fullscreenChangeSubscription: Subscription; private fullscreenChangeSubscription: Subscription;
private currentWindowHeight = window.innerHeight; private currentWindowHeight = window.innerHeight;
private layoutService: LayoutService;
/** /**
* @ignore * @ignore
*/ */
constructor( constructor(
private serviceConfig: ServiceConfigService,
private documentService: DocumentService, private documentService: DocumentService,
private chatService: ChatService, private chatService: ChatService,
private panelService: PanelService, private panelService: PanelService,
@ -355,7 +358,6 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
private oVDevicesService: DeviceService, private oVDevicesService: DeviceService,
private actionService: ActionService, private actionService: ActionService,
private loggerSrv: LoggerService, private loggerSrv: LoggerService,
private layoutService: LayoutService,
private cd: ChangeDetectorRef, private cd: ChangeDetectorRef,
private libService: OpenViduComponentsConfigService, private libService: OpenViduComponentsConfigService,
private platformService: PlatformService, private platformService: PlatformService,
@ -366,6 +368,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
private cdkOverlayService: CdkOverlayService private cdkOverlayService: CdkOverlayService
) { ) {
this.log = this.loggerSrv.get('ToolbarComponent'); this.log = this.loggerSrv.get('ToolbarComponent');
this.layoutService = this.serviceConfig.getLayoutService();
} }
/** /**
* @ignore * @ignore

View File

@ -1,8 +1,9 @@
import { ParticipantProperties } from '../models/participant.model'; import { ParticipantProperties } from '../models/participant.model';
export interface OpenViduComponentsConfig { export interface OpenViduComponentsConfig {
production?: boolean, production?: boolean;
participantFactory?: ParticipantFactoryFunction, participantFactory?: ParticipantFactoryFunction;
services?: any;
} }
export type ParticipantFactoryFunction = (props: ParticipantProperties) => any; export type ParticipantFactoryFunction = (props: ParticipantProperties) => any;

View File

@ -1,7 +1,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { ActivitiesPanelBroadcastingActivityDirective, ActivitiesPanelRecordingActivityDirective } from './activities-panel.directive'; import { ActivitiesPanelBroadcastingActivityDirective, ActivitiesPanelRecordingActivityDirective } from './activities-panel.directive';
import { AdminLoginErrorDirective, AdminDashboardRecordingsListDirective } from './admin.directive'; import { AdminLoginErrorDirective, AdminDashboardRecordingsListDirective } from './admin.directive';
import { LogoDirective } from './internals.directive'; import { LayoutRemoteParticipantsDirective, LogoDirective } from './internals.directive';
import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive'; import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive';
import { import {
StreamDisplayAudioDetectionDirective, StreamDisplayAudioDetectionDirective,
@ -76,7 +76,8 @@ import {
ActivitiesPanelRecordingActivityDirective, ActivitiesPanelRecordingActivityDirective,
ActivitiesPanelBroadcastingActivityDirective, ActivitiesPanelBroadcastingActivityDirective,
AdminDashboardRecordingsListDirective, AdminDashboardRecordingsListDirective,
AdminLoginErrorDirective AdminLoginErrorDirective,
LayoutRemoteParticipantsDirective
], ],
exports: [ exports: [
LivekitUrlDirective, LivekitUrlDirective,
@ -113,7 +114,8 @@ import {
ActivitiesPanelRecordingActivityDirective, ActivitiesPanelRecordingActivityDirective,
ActivitiesPanelBroadcastingActivityDirective, ActivitiesPanelBroadcastingActivityDirective,
AdminDashboardRecordingsListDirective, AdminDashboardRecordingsListDirective,
AdminLoginErrorDirective AdminLoginErrorDirective,
LayoutRemoteParticipantsDirective
] ]
}) })
export class ApiDirectiveModule {} export class ApiDirectiveModule {}

View File

@ -1,6 +1,8 @@
// * Private directives * // * Internal directives *
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; import { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { ParticipantModel } from '../../models/participant.model';
import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service';
/** /**
* Load default OpenVidu logo if custom one is not exist * Load default OpenVidu logo if custom one is not exist
@ -21,3 +23,35 @@ export class LogoDirective {
element.src = this.ovLogo || this.defaultLogo; element.src = this.ovLogo || this.defaultLogo;
} }
} }
/**
* @internal
*/
@Directive({
selector: 'ov-layout[ovRemoteParticipants]'
})
export class LayoutRemoteParticipantsDirective {
@Input() set ovRemoteParticipants(value: ParticipantModel[] | undefined) {
this.update(value);
}
constructor(
public elementRef: ElementRef,
private directiveService: OpenViduComponentsConfigService
) {}
ngOnDestroy(): void {
this.clear();
}
ngAfterViewInit() {
this.update(this.ovRemoteParticipants);
}
update(value: ParticipantModel[] | undefined) {
this.directiveService.setLayoutRemoteParticipants(value);
}
clear() {
this.update(undefined);
}
}

View File

@ -1,7 +1,7 @@
import { OverlayContainer } from '@angular/cdk/overlay'; import { OverlayContainer } from '@angular/cdk/overlay';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { ModuleWithProviders, NgModule } from '@angular/core'; import { ModuleWithProviders, NgModule, Provider } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { DeleteDialogComponent } from './components/dialogs/delete-recording.component'; import { DeleteDialogComponent } from './components/dialogs/delete-recording.component';
@ -25,7 +25,6 @@ import { CdkOverlayContainer } from './config/custom-cdk-overlay';
import { OpenViduComponentsConfig } from './config/openvidu-components-angular.config'; import { OpenViduComponentsConfig } from './config/openvidu-components-angular.config';
import { ActionService } from './services/action/action.service'; import { ActionService } from './services/action/action.service';
import { ChatService } from './services/chat/chat.service'; import { ChatService } from './services/chat/chat.service';
import { OpenViduComponentsConfigService } from './services/config/directive-config.service';
import { DeviceService } from './services/device/device.service'; import { DeviceService } from './services/device/device.service';
import { DocumentService } from './services/document/document.service'; import { DocumentService } from './services/document/document.service';
import { LayoutService } from './services/layout/layout.service'; import { LayoutService } from './services/layout/layout.service';
@ -65,6 +64,8 @@ import { AppMaterialModule } from './openvidu-components-angular.material.module
import { VirtualBackgroundService } from './services/virtual-background/virtual-background.service'; import { VirtualBackgroundService } from './services/virtual-background/virtual-background.service';
import { BroadcastingService } from './services/broadcasting/broadcasting.service'; import { BroadcastingService } from './services/broadcasting/broadcasting.service';
import { TranslateService } from './services/translate/translate.service'; import { TranslateService } from './services/translate/translate.service';
import { GlobalConfigService } from './services/config/global-config.service';
import { OpenViduComponentsConfigService } from './services/config/directive-config.service';
const publicComponents = [ const publicComponents = [
AdminDashboardComponent, AdminDashboardComponent,
@ -131,6 +132,8 @@ const privateComponents = [
DragDropModule DragDropModule
], ],
providers: [ providers: [
GlobalConfigService,
OpenViduComponentsConfigService,
ActionService, ActionService,
BroadcastingService, BroadcastingService,
// CaptionService, // CaptionService,
@ -139,7 +142,7 @@ const privateComponents = [
ChatService, ChatService,
DeviceService, DeviceService,
DocumentService, DocumentService,
LayoutService, // LayoutService,
LoggerService, LoggerService,
OpenViduService, OpenViduService,
PanelService, PanelService,
@ -153,12 +156,12 @@ const privateComponents = [
] ]
}) })
export class OpenViduComponentsModule { export class OpenViduComponentsModule {
static forRoot(config): ModuleWithProviders<OpenViduComponentsModule> { static forRoot(config: OpenViduComponentsConfig): ModuleWithProviders<OpenViduComponentsModule> {
// console.log(`${library.name} config: ${environment}`); const providers: Provider[] = [{ provide: 'OPENVIDU_COMPONENTS_CONFIG', useValue: config }];
const libConfig: OpenViduComponentsConfig = config;
return { return {
ngModule: OpenViduComponentsModule, ngModule: OpenViduComponentsModule,
providers: [OpenViduComponentsConfigService, { provide: 'OPENVIDU_COMPONENTS_CONFIG', useValue: libConfig }] providers
}; };
} }
} }

View File

@ -2,11 +2,14 @@ import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { RecordingInfo } from '../../models/recording.model'; import { RecordingInfo } from '../../models/recording.model';
import { ToolbarAdditionalButtonsPosition } from '../../models/toolbar.model'; import { ToolbarAdditionalButtonsPosition } from '../../models/toolbar.model';
import { ParticipantModel } from '../../models/participant.model';
/** /**
* @internal * @internal
*/ */
@Injectable() @Injectable({
providedIn: 'root'
})
export class OpenViduComponentsConfigService { export class OpenViduComponentsConfigService {
private token = <BehaviorSubject<string>>new BehaviorSubject(''); private token = <BehaviorSubject<string>>new BehaviorSubject('');
token$: Observable<string>; token$: Observable<string>;
@ -87,6 +90,10 @@ export class OpenViduComponentsConfigService {
private adminLoginError = <BehaviorSubject<any>>new BehaviorSubject(null); private adminLoginError = <BehaviorSubject<any>>new BehaviorSubject(null);
adminLoginError$: Observable<any>; adminLoginError$: Observable<any>;
// Internals
private layoutRemoteParticipants: BehaviorSubject<ParticipantModel[] | undefined> = new BehaviorSubject(<any>undefined);
layoutRemoteParticipants$: Observable<ParticipantModel[] | undefined>;
constructor() { constructor() {
this.token$ = this.token.asObservable(); this.token$ = this.token.asObservable();
this.livekitUrl$ = this.livekitUrl.asObservable(); this.livekitUrl$ = this.livekitUrl.asObservable();
@ -124,6 +131,8 @@ export class OpenViduComponentsConfigService {
// Admin dashboard // Admin dashboard
this.adminRecordingsList$ = this.adminRecordingsList.asObservable(); this.adminRecordingsList$ = this.adminRecordingsList.asObservable();
this.adminLoginError$ = this.adminLoginError.asObservable(); this.adminLoginError$ = this.adminLoginError.asObservable();
// Internals
this.layoutRemoteParticipants$ = this.layoutRemoteParticipants.asObservable();
} }
setToken(token: string) { setToken(token: string) {
@ -364,4 +373,9 @@ export class OpenViduComponentsConfigService {
isBroadcastingEnabled(): boolean { isBroadcastingEnabled(): boolean {
return this.broadcastingButton.getValue() && this.broadcastingActivity.getValue(); return this.broadcastingButton.getValue() && this.broadcastingActivity.getValue();
} }
// Internals
setLayoutRemoteParticipants(participants: ParticipantModel[] | undefined) {
this.layoutRemoteParticipants.next(participants);
}
} }

View File

@ -2,6 +2,9 @@ import { DOCUMENT } from '@angular/common';
import { Inject, Injectable} from '@angular/core'; import { Inject, Injectable} from '@angular/core';
import { ParticipantFactoryFunction, OpenViduComponentsConfig } from '../../config/openvidu-components-angular.config'; import { ParticipantFactoryFunction, OpenViduComponentsConfig } from '../../config/openvidu-components-angular.config';
/**
* @internal
*/
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })

View File

@ -0,0 +1,40 @@
import { Injectable, Inject, Injector, Type, Optional } from '@angular/core';
import { LayoutService } from '../layout/layout.service';
import { OpenViduComponentsConfig } from '../../config/openvidu-components-angular.config';
/**
* @internal
*/
@Injectable({
providedIn: 'root'
})
export class ServiceConfigService {
private configuration: OpenViduComponentsConfig;
constructor(
@Optional() private injector: Injector,
@Inject('OPENVIDU_COMPONENTS_CONFIG') config: OpenViduComponentsConfig
) {
this.configuration = config;
}
getLayoutService(): LayoutService {
return this.getServiceSafely<LayoutService>('LayoutService', LayoutService);
}
private getService<T>(key: string): T {
const service = this.configuration.services ? this.configuration.services[key] : null;
if (!service) {
throw new Error(`No service registered with key ${key}`);
}
return this.injector.get(service) as T;
}
private getServiceSafely<T>(key: string, fallback: new (...args: any[]) => T): T {
try {
return this.getService<T>(key);
} catch {
return this.injector.get(fallback);
}
}
}

View File

@ -1,6 +1,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { LayoutAlignment, LayoutClass, OpenViduLayout, OpenViduLayoutOptions } from '../../models/layout.model'; import { LayoutAlignment, LayoutClass, OpenViduLayout, OpenViduLayoutOptions } from '../../models/layout.model';
import { ILogger } from '../../models/logger.model';
import { LoggerService } from '../logger/logger.service';
/** /**
* @internal * @internal
@ -9,17 +11,19 @@ import { LayoutAlignment, LayoutClass, OpenViduLayout, OpenViduLayoutOptions } f
providedIn: 'root' providedIn: 'root'
}) })
export class LayoutService { export class LayoutService {
layoutContainer: HTMLElement | null = null; layoutContainer: HTMLElement | undefined = undefined;
layoutWidthObs: Observable<number>; layoutWidthObs: Observable<number>;
captionsTogglingObs: Observable<boolean>; captionsTogglingObs: Observable<boolean>;
private layoutWidth: BehaviorSubject<number> = new BehaviorSubject(0); protected layoutWidth: BehaviorSubject<number> = new BehaviorSubject(0);
private openviduLayout: OpenViduLayout; protected openviduLayout: OpenViduLayout | undefined;
private openviduLayoutOptions: OpenViduLayoutOptions; protected openviduLayoutOptions: OpenViduLayoutOptions;
private captionsToggling: BehaviorSubject<boolean> = new BehaviorSubject(false); protected captionsToggling: BehaviorSubject<boolean> = new BehaviorSubject(false);
protected log: ILogger;
constructor() { constructor(protected loggerSrv: LoggerService) {
this.layoutWidthObs = this.layoutWidth.asObservable(); this.layoutWidthObs = this.layoutWidth.asObservable();
this.captionsTogglingObs = this.captionsToggling.asObservable(); this.captionsTogglingObs = this.captionsToggling.asObservable();
this.log = this.loggerSrv.get('LayoutService');
} }
initialize(container: HTMLElement) { initialize(container: HTMLElement) {
@ -32,7 +36,33 @@ export class LayoutService {
this.sendLayoutWidthEvent(); this.sendLayoutWidthEvent();
} }
private getOptions(): OpenViduLayoutOptions { toggleCaptions() {
this.captionsToggling.next(!this.captionsToggling.getValue());
}
update(timeout: number | undefined = undefined) {
const updateAux = () => {
if (this.openviduLayout && this.layoutContainer) {
this.openviduLayout.updateLayout(this.layoutContainer, this.openviduLayoutOptions);
this.sendLayoutWidthEvent();
}
};
if (typeof timeout === 'number' && timeout >= 0) {
setTimeout(() => updateAux(), timeout);
} else {
updateAux();
}
}
getLayout() {
return this.openviduLayout;
}
clear() {
this.openviduLayout = undefined;
}
protected getOptions(): OpenViduLayoutOptions {
const options = { const options = {
maxRatio: 3 / 2, // The narrowest ratio that will be used (default 2x3) maxRatio: 3 / 2, // The narrowest ratio that will be used (default 2x3)
minRatio: 9 / 16, // The widest ratio that will be used (default 16x9) minRatio: 9 / 16, // The widest ratio that will be used (default 16x9)
@ -63,43 +93,19 @@ export class LayoutService {
return options; return options;
} }
toggleCaptions() { protected sendLayoutWidthEvent() {
this.captionsToggling.next(!this.captionsToggling.getValue()); const layoutContainer = this.openviduLayout?.getLayoutContainer();
} if (!layoutContainer) {
this.log.e('Layout container not found. Cannot send layout width event');
update(timeout: number = null) { return;
const updateAux = () => {
if (!!this.openviduLayout) {
this.openviduLayout.updateLayout(this.layoutContainer, this.openviduLayoutOptions);
this.sendLayoutWidthEvent();
}
};
if (typeof timeout === 'number' && timeout >= 0) {
setTimeout(() => updateAux(), timeout);
} else {
updateAux();
} }
} const sidenavLayoutElement = this.getHTMLElementByClassName(layoutContainer, LayoutClass.SIDENAV_CONTAINER);
getLayout() {
return this.openviduLayout;
}
clear() {
this.openviduLayout = null;
}
private sendLayoutWidthEvent() {
const sidenavLayoutElement = this.getHTMLElementByClassName(
this.openviduLayout?.getLayoutContainer(),
LayoutClass.SIDENAV_CONTAINER
);
if (sidenavLayoutElement && sidenavLayoutElement.clientWidth) { if (sidenavLayoutElement && sidenavLayoutElement.clientWidth) {
this.layoutWidth.next(sidenavLayoutElement.clientWidth); this.layoutWidth.next(sidenavLayoutElement.clientWidth);
} }
} }
private getHTMLElementByClassName(element: HTMLElement | null, className: string): HTMLElement | null { protected getHTMLElementByClassName(element: HTMLElement | null, className: string): HTMLElement | null {
while (!!element && element !== document.body) { while (!!element && element !== document.body) {
if (element.className.includes(className)) { if (element.className.includes(className)) {
return element; return element;

View File

@ -36,6 +36,7 @@ export * from './lib/models/recording.model';
export * from './lib/models/data-topic.model'; export * from './lib/models/data-topic.model';
export * from './lib/models/room.model'; export * from './lib/models/room.model';
export * from './lib/models/toolbar.model'; export * from './lib/models/toolbar.model';
export * from './lib/models/logger.model'
export * from './lib/openvidu-components-angular.module'; export * from './lib/openvidu-components-angular.module';
// Pipes // Pipes
export * from './lib/pipes/participant.pipe'; export * from './lib/pipes/participant.pipe';
@ -50,5 +51,6 @@ export * from './lib/services/panel/panel.service';
export * from './lib/services/participant/participant.service'; export * from './lib/services/participant/participant.service';
export * from './lib/services/recording/recording.service'; export * from './lib/services/recording/recording.service';
export * from './lib/services/config/global-config.service'; export * from './lib/services/config/global-config.service';
export * from './lib/services/logger/logger.service';
export * from 'livekit-client'; export * from 'livekit-client';