mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Refactor components to use takeUntil for unsubscribing from observables
- Replaced manual subscription management with takeUntil pattern - Introduced a destroy$ Subject in each component to handle unsubscriptions on component destruction. - Improved memory management and code readability by eliminating multiple subscription variables.master
parent
7573656060
commit
4dd007395f
|
@ -11,7 +11,7 @@ import {
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewContainerRef
|
ViewContainerRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { combineLatest, map, Subscription } from 'rxjs';
|
import { combineLatest, map, Subject, takeUntil } 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';
|
||||||
|
@ -72,11 +72,8 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
captionsEnabled = true;
|
captionsEnabled = true;
|
||||||
|
|
||||||
private localParticipantSubs: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private remoteParticipantsSubs: Subscription;
|
|
||||||
private captionsSubs: Subscription;
|
|
||||||
private resizeObserver: ResizeObserver;
|
private resizeObserver: ResizeObserver;
|
||||||
private cdkSubscription: Subscription;
|
|
||||||
private resizeTimeout: NodeJS.Timeout;
|
private resizeTimeout: NodeJS.Timeout;
|
||||||
private videoIsAtRight: boolean = false;
|
private videoIsAtRight: boolean = false;
|
||||||
private lastLayoutWidth: number = 0;
|
private lastLayoutWidth: number = 0;
|
||||||
|
@ -107,13 +104,11 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
this.localParticipant = undefined;
|
this.localParticipant = undefined;
|
||||||
this.remoteParticipants = [];
|
this.remoteParticipants = [];
|
||||||
this.resizeObserver?.disconnect();
|
this.resizeObserver?.disconnect();
|
||||||
this.localParticipantSubs?.unsubscribe();
|
|
||||||
this.remoteParticipantsSubs?.unsubscribe();
|
|
||||||
this.captionsSubs?.unsubscribe();
|
|
||||||
this.cdkSubscription?.unsubscribe();
|
|
||||||
this.layoutService.clear();
|
this.layoutService.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,33 +122,38 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToCaptions() {
|
private subscribeToCaptions() {
|
||||||
this.captionsSubs = this.layoutService.captionsTogglingObs.subscribe((value: boolean) => {
|
this.layoutService.captionsTogglingObs
|
||||||
this.captionsEnabled = value;
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.cd.markForCheck();
|
.subscribe((value: boolean) => {
|
||||||
this.layoutService.update();
|
this.captionsEnabled = value;
|
||||||
});
|
this.cd.markForCheck();
|
||||||
|
this.layoutService.update();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToParticipants() {
|
private subscribeToParticipants() {
|
||||||
this.localParticipantSubs = this.participantService.localParticipant$.subscribe((p) => {
|
this.participantService.localParticipant$
|
||||||
if (p) {
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.localParticipant = p;
|
.subscribe((p) => {
|
||||||
if (!this.localParticipant?.isMinimized) {
|
if (p) {
|
||||||
this.videoIsAtRight = false;
|
this.localParticipant = p;
|
||||||
|
if (!this.localParticipant?.isMinimized) {
|
||||||
|
this.videoIsAtRight = false;
|
||||||
|
}
|
||||||
|
this.layoutService.update();
|
||||||
|
this.cd.markForCheck();
|
||||||
}
|
}
|
||||||
this.layoutService.update();
|
});
|
||||||
this.cd.markForCheck();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.remoteParticipantsSubs = combineLatest([
|
combineLatest([
|
||||||
this.participantService.remoteParticipants$,
|
this.participantService.remoteParticipants$,
|
||||||
this.directiveService.layoutRemoteParticipants$
|
this.directiveService.layoutRemoteParticipants$
|
||||||
])
|
])
|
||||||
.pipe(
|
.pipe(
|
||||||
map(([serviceParticipants, directiveParticipants]) =>
|
map(([serviceParticipants, directiveParticipants]) =>
|
||||||
directiveParticipants !== undefined ? directiveParticipants : serviceParticipants
|
directiveParticipants !== undefined ? directiveParticipants : serviceParticipants
|
||||||
)
|
),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
)
|
)
|
||||||
.subscribe((participants) => {
|
.subscribe((participants) => {
|
||||||
this.remoteParticipants = participants;
|
this.remoteParticipants = participants;
|
||||||
|
@ -218,7 +218,10 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.videoIsAtRight = false;
|
this.videoIsAtRight = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.cdkSubscription = this.cdkDrag.released.subscribe(handler);
|
|
||||||
|
this.cdkDrag.released
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(handler);
|
||||||
|
|
||||||
if (this.globalService.isProduction()) return;
|
if (this.globalService.isProduction()) return;
|
||||||
// Just for allow E2E testing with drag and drop
|
// Just for allow E2E testing with drag and drop
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { PanelStatusInfo, PanelType } from '../../../models/panel.model';
|
import { PanelStatusInfo, PanelType } from '../../../models/panel.model';
|
||||||
import { OpenViduComponentsConfigService } from '../../../services/config/directive-config.service';
|
import { OpenViduComponentsConfigService } from '../../../services/config/directive-config.service';
|
||||||
import { PanelService } from '../../../services/panel/panel.service';
|
import { PanelService } from '../../../services/panel/panel.service';
|
||||||
|
@ -80,9 +80,7 @@ export class ActivitiesPanelComponent implements OnInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
showBroadcastingActivity: boolean = true;
|
showBroadcastingActivity: boolean = true;
|
||||||
private panelSubscription: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private recordingActivitySub: Subscription;
|
|
||||||
private broadcastingActivitySub: Subscription;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -105,9 +103,8 @@ export class ActivitiesPanelComponent implements OnInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.panelSubscription) this.panelSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
if (this.recordingActivitySub) this.recordingActivitySub.unsubscribe();
|
this.destroy$.complete();
|
||||||
if (this.broadcastingActivitySub) this.broadcastingActivitySub.unsubscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,7 +115,7 @@ export class ActivitiesPanelComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToPanelToggling() {
|
private subscribeToPanelToggling() {
|
||||||
this.panelSubscription = this.panelService.panelStatusObs.subscribe((ev: PanelStatusInfo) => {
|
this.panelService.panelStatusObs.pipe(takeUntil(this.destroy$)).subscribe((ev: PanelStatusInfo) => {
|
||||||
if (ev.panelType === PanelType.ACTIVITIES && !!ev.subOptionType) {
|
if (ev.panelType === PanelType.ACTIVITIES && !!ev.subOptionType) {
|
||||||
this.expandedPanel = ev.subOptionType;
|
this.expandedPanel = ev.subOptionType;
|
||||||
}
|
}
|
||||||
|
@ -126,12 +123,12 @@ export class ActivitiesPanelComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToActivitiesPanelDirective() {
|
private subscribeToActivitiesPanelDirective() {
|
||||||
this.recordingActivitySub = this.libService.recordingActivity$.subscribe((value: boolean) => {
|
this.libService.recordingActivity$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showRecordingActivity = value;
|
this.showRecordingActivity = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.broadcastingActivitySub = this.libService.broadcastingActivity$.subscribe((value: boolean) => {
|
this.libService.broadcastingActivity$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showBroadcastingActivity = value;
|
this.showBroadcastingActivity = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
BroadcastingStartRequestedEvent,
|
BroadcastingStartRequestedEvent,
|
||||||
BroadcastingStatus,
|
BroadcastingStatus,
|
||||||
|
@ -76,7 +76,7 @@ export class BroadcastingActivityComponent implements OnInit {
|
||||||
*/
|
*/
|
||||||
isPanelOpened: boolean = false;
|
isPanelOpened: boolean = false;
|
||||||
|
|
||||||
private broadcastingSub: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -99,7 +99,8 @@ export class BroadcastingActivityComponent implements OnInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.broadcastingSub) this.broadcastingSub.unsubscribe();
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -147,7 +148,7 @@ export class BroadcastingActivityComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToBroadcastingStatus() {
|
private subscribeToBroadcastingStatus() {
|
||||||
this.broadcastingSub = this.broadcastingService.broadcastingStatusObs.subscribe((event: BroadcastingStatusInfo | undefined) => {
|
this.broadcastingService.broadcastingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: BroadcastingStatusInfo | undefined) => {
|
||||||
if (!!event) {
|
if (!!event) {
|
||||||
const { status, broadcastingId, error } = event;
|
const { status, broadcastingId, error } = event;
|
||||||
this.broadcastingStatus = status;
|
this.broadcastingStatus = status;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
RecordingDeleteRequestedEvent,
|
RecordingDeleteRequestedEvent,
|
||||||
RecordingDownloadClickedEvent,
|
RecordingDownloadClickedEvent,
|
||||||
|
@ -109,8 +109,7 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
*/
|
*/
|
||||||
mouseHovering: boolean = false;
|
mouseHovering: boolean = false;
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private recordingStatusSubscription: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private tracksSubscription: Subscription;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -138,8 +137,8 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.recordingStatusSubscription) this.recordingStatusSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
if (this.tracksSubscription) this.tracksSubscription.unsubscribe();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -242,7 +241,7 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToRecordingStatus() {
|
private subscribeToRecordingStatus() {
|
||||||
this.recordingStatusSubscription = this.recordingService.recordingStatusObs.subscribe((event: RecordingStatusInfo) => {
|
this.recordingService.recordingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: RecordingStatusInfo) => {
|
||||||
const { status, recordingList, error } = event;
|
const { status, recordingList, error } = event;
|
||||||
this.recordingStatus = status;
|
this.recordingStatus = status;
|
||||||
this.recordingList = recordingList;
|
this.recordingList = recordingList;
|
||||||
|
@ -258,7 +257,7 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
private subscribeToTracksChanges() {
|
private subscribeToTracksChanges() {
|
||||||
this.hasRoomTracksPublished = this.openviduService.hasRoomTracksPublished();
|
this.hasRoomTracksPublished = this.openviduService.hasRoomTracksPublished();
|
||||||
|
|
||||||
this.tracksSubscription = this.participantService.localParticipant$.subscribe(() => {
|
this.participantService.localParticipant$.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||||
const newValue = this.openviduService.hasRoomTracksPublished();
|
const newValue = this.openviduService.hasRoomTracksPublished();
|
||||||
if (this.hasRoomTracksPublished !== newValue) {
|
if (this.hasRoomTracksPublished !== newValue) {
|
||||||
this.hasRoomTracksPublished = newValue;
|
this.hasRoomTracksPublished = newValue;
|
||||||
|
@ -266,7 +265,7 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.participantService.remoteParticipants$.subscribe(() => {
|
this.participantService.remoteParticipants$.pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||||
const newValue = this.openviduService.hasRoomTracksPublished();
|
const newValue = this.openviduService.hasRoomTracksPublished();
|
||||||
if (this.hasRoomTracksPublished !== newValue) {
|
if (this.hasRoomTracksPublished !== newValue) {
|
||||||
this.hasRoomTracksPublished = newValue;
|
this.hasRoomTracksPublished = newValue;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { ChatMessage } from '../../../models/chat.model';
|
import { ChatMessage } from '../../../models/chat.model';
|
||||||
import { PanelType } from '../../../models/panel.model';
|
import { PanelType } from '../../../models/panel.model';
|
||||||
import { ChatService } from '../../../services/chat/chat.service';
|
import { ChatService } from '../../../services/chat/chat.service';
|
||||||
|
@ -34,7 +34,7 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
messageList: ChatMessage[] = [];
|
messageList: ChatMessage[] = [];
|
||||||
|
|
||||||
private chatMessageSubscription: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
|
@ -66,7 +66,8 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.chatMessageSubscription) this.chatMessageSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,7 +110,7 @@ export class ChatPanelComponent implements OnInit, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToMessages() {
|
private subscribeToMessages() {
|
||||||
this.chatMessageSubscription = this.chatService.messagesObs.subscribe((messages: ChatMessage[]) => {
|
this.chatService.messagesObs.pipe(takeUntil(this.destroy$)).subscribe((messages: ChatMessage[]) => {
|
||||||
this.messageList = messages;
|
this.messageList = messages;
|
||||||
if (this.panelService.isChatPanelOpened()) {
|
if (this.panelService.isChatPanelOpened()) {
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
Output,
|
Output,
|
||||||
TemplateRef
|
TemplateRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { skip, Subscription } from 'rxjs';
|
import { skip, Subject, takeUntil } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
ActivitiesPanelDirective,
|
ActivitiesPanelDirective,
|
||||||
AdditionalPanelsDirective,
|
AdditionalPanelsDirective,
|
||||||
|
@ -195,7 +195,7 @@ export class PanelComponent implements OnInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
isExternalPanelOpened: boolean;
|
isExternalPanelOpened: boolean;
|
||||||
private panelSubscription: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
private panelEmitersHandler: Map<
|
private panelEmitersHandler: Map<
|
||||||
PanelType,
|
PanelType,
|
||||||
|
@ -226,11 +226,12 @@ export class PanelComponent implements OnInit {
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.isChatPanelOpened = false;
|
this.isChatPanelOpened = false;
|
||||||
this.isParticipantsPanelOpened = false;
|
this.isParticipantsPanelOpened = false;
|
||||||
if (this.panelSubscription) this.panelSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToPanelToggling() {
|
private subscribeToPanelToggling() {
|
||||||
this.panelSubscription = this.panelService.panelStatusObs.pipe(skip(1)).subscribe((ev: PanelStatusInfo) => {
|
this.panelService.panelStatusObs.pipe(skip(1), takeUntil(this.destroy$)).subscribe((ev: PanelStatusInfo) => {
|
||||||
this.isChatPanelOpened = ev.isOpened && ev.panelType === PanelType.CHAT;
|
this.isChatPanelOpened = ev.isOpened && ev.panelType === PanelType.CHAT;
|
||||||
this.isParticipantsPanelOpened = ev.isOpened && ev.panelType === PanelType.PARTICIPANTS;
|
this.isParticipantsPanelOpened = ev.isOpened && ev.panelType === PanelType.PARTICIPANTS;
|
||||||
this.isBackgroundEffectsPanelOpened = ev.isOpened && ev.panelType === PanelType.BACKGROUND_EFFECTS;
|
this.isBackgroundEffectsPanelOpened = ev.isOpened && ev.panelType === PanelType.BACKGROUND_EFFECTS;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import { PanelStatusInfo, PanelSettingsOptions, PanelType } from '../../../models/panel.model';
|
import { PanelStatusInfo, PanelSettingsOptions, PanelType } from '../../../models/panel.model';
|
||||||
import { OpenViduComponentsConfigService } from '../../../services/config/directive-config.service';
|
import { OpenViduComponentsConfigService } from '../../../services/config/directive-config.service';
|
||||||
import { PanelService } from '../../../services/panel/panel.service';
|
import { PanelService } from '../../../services/panel/panel.service';
|
||||||
|
@ -27,11 +27,8 @@ export class SettingsPanelComponent implements OnInit {
|
||||||
showCameraButton: boolean = true;
|
showCameraButton: boolean = true;
|
||||||
showMicrophoneButton: boolean = true;
|
showMicrophoneButton: boolean = true;
|
||||||
showCaptions: boolean = true;
|
showCaptions: boolean = true;
|
||||||
panelSubscription: Subscription;
|
|
||||||
isMobile: boolean = false;
|
isMobile: boolean = false;
|
||||||
private cameraButtonSub: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private microphoneButtonSub: Subscription;
|
|
||||||
private captionsSubs: Subscription;
|
|
||||||
constructor(
|
constructor(
|
||||||
private panelService: PanelService,
|
private panelService: PanelService,
|
||||||
private platformService: PlatformService,
|
private platformService: PlatformService,
|
||||||
|
@ -44,10 +41,8 @@ export class SettingsPanelComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.panelSubscription) this.panelSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
if (this.cameraButtonSub) this.cameraButtonSub.unsubscribe();
|
this.destroy$.complete();
|
||||||
if (this.microphoneButtonSub) this.microphoneButtonSub.unsubscribe();
|
|
||||||
if (this.captionsSubs) this.captionsSubs.unsubscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
@ -58,13 +53,13 @@ export class SettingsPanelComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToDirectives() {
|
private subscribeToDirectives() {
|
||||||
this.cameraButtonSub = this.libService.cameraButton$.subscribe((value: boolean) => (this.showCameraButton = value));
|
this.libService.cameraButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showCameraButton = value));
|
||||||
this.microphoneButtonSub = this.libService.microphoneButton$.subscribe((value: boolean) => (this.showMicrophoneButton = value));
|
this.libService.microphoneButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showMicrophoneButton = value));
|
||||||
this.captionsSubs = this.libService.captionsButton$.subscribe((value: boolean) => (this.showCaptions = value));
|
this.libService.captionsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showCaptions = value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToPanelToggling() {
|
private subscribeToPanelToggling() {
|
||||||
this.panelSubscription = this.panelService.panelStatusObs.subscribe((ev: PanelStatusInfo) => {
|
this.panelService.panelStatusObs.pipe(takeUntil(this.destroy$)).subscribe((ev: PanelStatusInfo) => {
|
||||||
if (ev.panelType === PanelType.SETTINGS && !!ev.subOptionType) {
|
if (ev.panelType === PanelType.SETTINGS && !!ev.subOptionType) {
|
||||||
this.selectedOption = ev.subOptionType as PanelSettingsOptions;
|
this.selectedOption = ev.subOptionType as PanelSettingsOptions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
OnInit,
|
OnInit,
|
||||||
Output
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } 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';
|
||||||
|
@ -61,11 +61,7 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
audioTrack: LocalTrack | undefined;
|
audioTrack: LocalTrack | undefined;
|
||||||
private tracks: LocalTrack[];
|
private tracks: LocalTrack[];
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private cameraButtonSub: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private microphoneButtonSub: Subscription;
|
|
||||||
private minimalSub: Subscription;
|
|
||||||
private displayLogoSub: Subscription;
|
|
||||||
private displayParticipantNameSub: Subscription;
|
|
||||||
private shouldRemoveTracksWhenComponentIsDestroyed: boolean = true;
|
private shouldRemoveTracksWhenComponentIsDestroyed: boolean = true;
|
||||||
|
|
||||||
@HostListener('window:resize')
|
@HostListener('window:resize')
|
||||||
|
@ -99,12 +95,9 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
async ngOnDestroy() {
|
async ngOnDestroy() {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
this.cdkSrv.setSelector('body');
|
this.cdkSrv.setSelector('body');
|
||||||
if (this.minimalSub) this.minimalSub.unsubscribe();
|
|
||||||
if (this.cameraButtonSub) this.cameraButtonSub.unsubscribe();
|
|
||||||
if (this.microphoneButtonSub) this.microphoneButtonSub.unsubscribe();
|
|
||||||
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
|
|
||||||
if (this.displayParticipantNameSub) this.displayParticipantNameSub.unsubscribe();
|
|
||||||
|
|
||||||
if (this.shouldRemoveTracksWhenComponentIsDestroyed) {
|
if (this.shouldRemoveTracksWhenComponentIsDestroyed) {
|
||||||
this.tracks.forEach((track) => {
|
this.tracks.forEach((track) => {
|
||||||
|
@ -154,32 +147,49 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToPrejoinDirectives() {
|
private subscribeToPrejoinDirectives() {
|
||||||
this.minimalSub = this.libService.minimal$.subscribe((value: boolean) => {
|
this.libService.minimal$
|
||||||
this.isMinimal = value;
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.changeDetector.markForCheck();
|
.subscribe((value: boolean) => {
|
||||||
});
|
this.isMinimal = value;
|
||||||
this.cameraButtonSub = this.libService.cameraButton$.subscribe((value: boolean) => {
|
|
||||||
this.showCameraButton = value;
|
|
||||||
this.changeDetector.markForCheck();
|
|
||||||
});
|
|
||||||
this.microphoneButtonSub = this.libService.microphoneButton$.subscribe((value: boolean) => {
|
|
||||||
this.showMicrophoneButton = value;
|
|
||||||
this.changeDetector.markForCheck();
|
|
||||||
});
|
|
||||||
this.displayLogoSub = this.libService.displayLogo$.subscribe((value: boolean) => {
|
|
||||||
this.showLogo = value;
|
|
||||||
this.changeDetector.markForCheck();
|
|
||||||
});
|
|
||||||
this.libService.participantName$.subscribe((value: string) => {
|
|
||||||
if (value) {
|
|
||||||
this.participantName = value;
|
|
||||||
this.changeDetector.markForCheck();
|
this.changeDetector.markForCheck();
|
||||||
}
|
});
|
||||||
});
|
|
||||||
this.displayParticipantNameSub = this.libService.prejoinDisplayParticipantName$.subscribe((value: boolean) => {
|
this.libService.cameraButton$
|
||||||
this.showParticipantName = value;
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.changeDetector.markForCheck();
|
.subscribe((value: boolean) => {
|
||||||
});
|
this.showCameraButton = value;
|
||||||
|
this.changeDetector.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.microphoneButton$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: boolean) => {
|
||||||
|
this.showMicrophoneButton = value;
|
||||||
|
this.changeDetector.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.displayLogo$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: boolean) => {
|
||||||
|
this.showLogo = value;
|
||||||
|
this.changeDetector.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.participantName$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: string) => {
|
||||||
|
if (value) {
|
||||||
|
this.participantName = value;
|
||||||
|
this.changeDetector.markForCheck();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.prejoinDisplayParticipantName$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: boolean) => {
|
||||||
|
this.showParticipantName = value;
|
||||||
|
this.changeDetector.markForCheck();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async videoEnabledChanged(enabled: boolean) {
|
async videoEnabledChanged(enabled: boolean) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
import { ILogger } from '../../models/logger.model';
|
import { ILogger } from '../../models/logger.model';
|
||||||
import { animate, style, transition, trigger } from '@angular/animations';
|
import { animate, style, transition, trigger } from '@angular/animations';
|
||||||
import { MatDrawerContainer, MatSidenav } from '@angular/material/sidenav';
|
import { MatDrawerContainer, MatSidenav } from '@angular/material/sidenav';
|
||||||
import { skip, Subscription } from 'rxjs';
|
import { skip, Subject, takeUntil } from 'rxjs';
|
||||||
import { SidenavMode } from '../../models/layout.model';
|
import { SidenavMode } from '../../models/layout.model';
|
||||||
import { PanelStatusInfo, PanelType } from '../../models/panel.model';
|
import { PanelStatusInfo, PanelType } from '../../models/panel.model';
|
||||||
import { DataTopic } from '../../models/data-topic.model';
|
import { DataTopic } from '../../models/data-topic.model';
|
||||||
|
@ -105,10 +105,8 @@ export class SessionComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
private shouldDisconnectRoomWhenComponentIsDestroyed: boolean = true;
|
private shouldDisconnectRoomWhenComponentIsDestroyed: boolean = true;
|
||||||
private readonly SIDENAV_WIDTH_LIMIT_MODE = 790;
|
private readonly SIDENAV_WIDTH_LIMIT_MODE = 790;
|
||||||
private menuSubscription: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private layoutWidthSubscription: Subscription;
|
|
||||||
private updateLayoutInterval: NodeJS.Timeout;
|
private updateLayoutInterval: NodeJS.Timeout;
|
||||||
private captionLanguageSubscription: Subscription;
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -238,8 +236,8 @@ export class SessionComponent implements OnInit, OnDestroy {
|
||||||
if (this.room) this.room.removeAllListeners();
|
if (this.room) this.room.removeAllListeners();
|
||||||
this.participantService.clear();
|
this.participantService.clear();
|
||||||
// this.room = undefined;
|
// this.room = undefined;
|
||||||
if (this.menuSubscription) this.menuSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
if (this.layoutWidthSubscription) this.layoutWidthSubscription.unsubscribe();
|
this.destroy$.complete();
|
||||||
// if (this.captionLanguageSubscription) this.captionLanguageSubscription.unsubscribe();
|
// if (this.captionLanguageSubscription) this.captionLanguageSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +267,7 @@ export class SessionComponent implements OnInit, OnDestroy {
|
||||||
this.startUpdateLayoutInterval();
|
this.startUpdateLayoutInterval();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.menuSubscription = this.panelService.panelStatusObs.pipe(skip(1)).subscribe((ev: PanelStatusInfo) => {
|
this.panelService.panelStatusObs.pipe(skip(1), takeUntil(this.destroy$)).subscribe((ev: PanelStatusInfo) => {
|
||||||
if (this.sideMenu) {
|
if (this.sideMenu) {
|
||||||
this.settingsPanelOpened = ev.isOpened && ev.panelType === PanelType.SETTINGS;
|
this.settingsPanelOpened = ev.isOpened && ev.panelType === PanelType.SETTINGS;
|
||||||
|
|
||||||
|
@ -288,7 +286,7 @@ export class SessionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToLayoutWidth() {
|
private subscribeToLayoutWidth() {
|
||||||
this.layoutWidthSubscription = this.layoutService.layoutWidthObs.subscribe((width) => {
|
this.layoutService.layoutWidthObs.pipe(takeUntil(this.destroy$)).subscribe((width) => {
|
||||||
this.sidenavMode = width <= this.SIDENAV_WIDTH_LIMIT_MODE ? SidenavMode.OVER : SidenavMode.SIDE;
|
this.sidenavMode = width <= this.SIDENAV_WIDTH_LIMIT_MODE ? SidenavMode.OVER : SidenavMode.SIDE;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu';
|
import { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, takeUntil } 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';
|
||||||
|
@ -92,10 +92,7 @@ export class StreamComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _streamContainer: ElementRef;
|
private _streamContainer: ElementRef;
|
||||||
private minimalSub: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private displayParticipantNameSub: Subscription;
|
|
||||||
private displayAudioDetectionSub: Subscription;
|
|
||||||
private videoControlsSub: Subscription;
|
|
||||||
private readonly HOVER_TIMEOUT = 3000;
|
private readonly HOVER_TIMEOUT = 3000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,11 +110,9 @@ export class StreamComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
this.cdkSrv.setSelector('body');
|
this.cdkSrv.setSelector('body');
|
||||||
if (this.videoControlsSub) this.videoControlsSub.unsubscribe();
|
|
||||||
if (this.displayAudioDetectionSub) this.displayAudioDetectionSub.unsubscribe();
|
|
||||||
if (this.displayParticipantNameSub) this.displayParticipantNameSub.unsubscribe();
|
|
||||||
if (this.minimalSub) this.minimalSub.unsubscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,20 +178,31 @@ export class StreamComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToStreamDirectives() {
|
private subscribeToStreamDirectives() {
|
||||||
this.minimalSub = this.libService.minimal$.subscribe((value: boolean) => {
|
this.libService.minimal$
|
||||||
this.isMinimal = value;
|
.pipe(takeUntil(this.destroy$))
|
||||||
});
|
.subscribe((value: boolean) => {
|
||||||
this.displayParticipantNameSub = this.libService.displayParticipantName$.subscribe((value: boolean) => {
|
this.isMinimal = value;
|
||||||
this.showParticipantName = value;
|
});
|
||||||
// this.cd.markForCheck();
|
|
||||||
});
|
this.libService.displayParticipantName$
|
||||||
this.displayAudioDetectionSub = this.libService.displayAudioDetection$.subscribe((value: boolean) => {
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.showAudioDetection = value;
|
.subscribe((value: boolean) => {
|
||||||
// this.cd.markForCheck();
|
this.showParticipantName = value;
|
||||||
});
|
// this.cd.markForCheck();
|
||||||
this.videoControlsSub = this.libService.streamVideoControls$.subscribe((value: boolean) => {
|
});
|
||||||
this.showVideoControls = value;
|
|
||||||
// this.cd.markForCheck();
|
this.libService.displayAudioDetection$
|
||||||
});
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: boolean) => {
|
||||||
|
this.showAudioDetection = value;
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.streamVideoControls$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: boolean) => {
|
||||||
|
this.showVideoControls = value;
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { fromEvent, skip, Subscription } from 'rxjs';
|
import { fromEvent, skip, Subject, takeUntil } from 'rxjs';
|
||||||
import { ChatService } from '../../services/chat/chat.service';
|
import { ChatService } from '../../services/chat/chat.service';
|
||||||
import { DocumentService } from '../../services/document/document.service';
|
import { DocumentService } from '../../services/document/document.service';
|
||||||
import { PanelService } from '../../services/panel/panel.service';
|
import { PanelService } from '../../services/panel/panel.service';
|
||||||
|
@ -340,30 +340,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
recordingTime: Date;
|
recordingTime: Date;
|
||||||
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private minimalSub: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private panelTogglingSubscription: Subscription;
|
|
||||||
private chatMessagesSubscription: Subscription;
|
|
||||||
private localParticipantSubscription: Subscription;
|
|
||||||
private cameraButtonSub: Subscription;
|
|
||||||
private microphoneButtonSub: Subscription;
|
|
||||||
private screenshareButtonSub: Subscription;
|
|
||||||
private fullscreenButtonSub: Subscription;
|
|
||||||
private backgroundEffectsButtonSub: Subscription;
|
|
||||||
private leaveButtonSub: Subscription;
|
|
||||||
private recordingButtonSub: Subscription;
|
|
||||||
private broadcastingButtonSub: Subscription;
|
|
||||||
private recordingSubscription: Subscription;
|
|
||||||
private broadcastingSubscription: Subscription;
|
|
||||||
private activitiesPanelButtonSub: Subscription;
|
|
||||||
private participantsPanelButtonSub: Subscription;
|
|
||||||
private chatPanelButtonSub: Subscription;
|
|
||||||
private displayLogoSub: Subscription;
|
|
||||||
private brandingLogoSub: Subscription;
|
|
||||||
private displayRoomNameSub: Subscription;
|
|
||||||
private settingsButtonSub: Subscription;
|
|
||||||
private captionsSubs: Subscription;
|
|
||||||
private additionalButtonsPositionSub: Subscription;
|
|
||||||
private fullscreenChangeSubscription: Subscription;
|
|
||||||
private currentWindowHeight = window.innerHeight;
|
private currentWindowHeight = window.innerHeight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -437,30 +414,8 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.panelService.clear();
|
this.panelService.clear();
|
||||||
if (this.panelTogglingSubscription) this.panelTogglingSubscription.unsubscribe();
|
this.destroy$.next();
|
||||||
if (this.chatMessagesSubscription) this.chatMessagesSubscription.unsubscribe();
|
this.destroy$.complete();
|
||||||
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
|
|
||||||
if (this.cameraButtonSub) this.cameraButtonSub.unsubscribe();
|
|
||||||
if (this.microphoneButtonSub) this.microphoneButtonSub.unsubscribe();
|
|
||||||
if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe();
|
|
||||||
if (this.fullscreenButtonSub) this.fullscreenButtonSub.unsubscribe();
|
|
||||||
if (this.backgroundEffectsButtonSub) this.backgroundEffectsButtonSub.unsubscribe();
|
|
||||||
if (this.leaveButtonSub) this.leaveButtonSub.unsubscribe();
|
|
||||||
if (this.recordingButtonSub) this.recordingButtonSub.unsubscribe();
|
|
||||||
if (this.broadcastingButtonSub) this.broadcastingButtonSub.unsubscribe();
|
|
||||||
if (this.participantsPanelButtonSub) this.participantsPanelButtonSub.unsubscribe();
|
|
||||||
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
|
|
||||||
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
|
|
||||||
if (this.brandingLogoSub) this.brandingLogoSub.unsubscribe();
|
|
||||||
if (this.displayRoomNameSub) this.displayRoomNameSub.unsubscribe();
|
|
||||||
if (this.minimalSub) this.minimalSub.unsubscribe();
|
|
||||||
if (this.activitiesPanelButtonSub) this.activitiesPanelButtonSub.unsubscribe();
|
|
||||||
if (this.recordingSubscription) this.recordingSubscription.unsubscribe();
|
|
||||||
if (this.broadcastingSubscription) this.broadcastingSubscription.unsubscribe();
|
|
||||||
if (this.settingsButtonSub) this.settingsButtonSub.unsubscribe();
|
|
||||||
if (this.captionsSubs) this.captionsSubs.unsubscribe();
|
|
||||||
if (this.fullscreenChangeSubscription) this.fullscreenChangeSubscription.unsubscribe();
|
|
||||||
if (this.additionalButtonsPositionSub) this.additionalButtonsPositionSub.unsubscribe();
|
|
||||||
this.isFullscreenActive = false;
|
this.isFullscreenActive = false;
|
||||||
this.cdkOverlayService.setSelector('body');
|
this.cdkOverlayService.setSelector('body');
|
||||||
}
|
}
|
||||||
|
@ -647,7 +602,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToFullscreenChanged() {
|
private subscribeToFullscreenChanged() {
|
||||||
this.fullscreenChangeSubscription = fromEvent(document, 'fullscreenchange').subscribe(() => {
|
fromEvent(document, 'fullscreenchange').pipe(takeUntil(this.destroy$)).subscribe(() => {
|
||||||
const isFullscreen = Boolean(document.fullscreenElement);
|
const isFullscreen = Boolean(document.fullscreenElement);
|
||||||
if (isFullscreen) {
|
if (isFullscreen) {
|
||||||
this.cdkOverlayService.setSelector('#session-container');
|
this.cdkOverlayService.setSelector('#session-container');
|
||||||
|
@ -661,7 +616,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToMenuToggling() {
|
private subscribeToMenuToggling() {
|
||||||
this.panelTogglingSubscription = this.panelService.panelStatusObs.subscribe((ev: PanelStatusInfo) => {
|
this.panelService.panelStatusObs.pipe(takeUntil(this.destroy$)).subscribe((ev: PanelStatusInfo) => {
|
||||||
this.isChatOpened = ev.isOpened && ev.panelType === PanelType.CHAT;
|
this.isChatOpened = ev.isOpened && ev.panelType === PanelType.CHAT;
|
||||||
this.isParticipantsOpened = ev.isOpened && ev.panelType === PanelType.PARTICIPANTS;
|
this.isParticipantsOpened = ev.isOpened && ev.panelType === PanelType.PARTICIPANTS;
|
||||||
this.isActivitiesOpened = ev.isOpened && ev.panelType === PanelType.ACTIVITIES;
|
this.isActivitiesOpened = ev.isOpened && ev.panelType === PanelType.ACTIVITIES;
|
||||||
|
@ -673,7 +628,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToChatMessages() {
|
private subscribeToChatMessages() {
|
||||||
this.chatMessagesSubscription = this.chatService.messagesObs.pipe(skip(1)).subscribe((messages) => {
|
this.chatService.messagesObs.pipe(skip(1), takeUntil(this.destroy$)).subscribe((messages) => {
|
||||||
if (!this.panelService.isChatPanelOpened()) {
|
if (!this.panelService.isChatPanelOpened()) {
|
||||||
this.unreadMessages++;
|
this.unreadMessages++;
|
||||||
}
|
}
|
||||||
|
@ -682,7 +637,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private subscribeToUserMediaProperties() {
|
private subscribeToUserMediaProperties() {
|
||||||
this.localParticipantSubscription = this.participantService.localParticipant$.subscribe((p: ParticipantModel | undefined) => {
|
this.participantService.localParticipant$.pipe(takeUntil(this.destroy$)).subscribe((p: ParticipantModel | undefined) => {
|
||||||
if (p) {
|
if (p) {
|
||||||
if (this.isCameraEnabled !== p.isCameraEnabled) {
|
if (this.isCameraEnabled !== p.isCameraEnabled) {
|
||||||
this.onVideoEnabledChanged.emit(p.isCameraEnabled);
|
this.onVideoEnabledChanged.emit(p.isCameraEnabled);
|
||||||
|
@ -706,7 +661,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToRecordingStatus() {
|
private subscribeToRecordingStatus() {
|
||||||
this.recordingSubscription = this.recordingService.recordingStatusObs.subscribe((event: RecordingStatusInfo) => {
|
this.recordingService.recordingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: RecordingStatusInfo) => {
|
||||||
const { status, startedAt } = event;
|
const { status, startedAt } = event;
|
||||||
this.recordingStatus = status;
|
this.recordingStatus = status;
|
||||||
if (status === RecordingStatus.STARTED) {
|
if (status === RecordingStatus.STARTED) {
|
||||||
|
@ -723,7 +678,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToBroadcastingStatus() {
|
private subscribeToBroadcastingStatus() {
|
||||||
this.broadcastingSubscription = this.broadcastingService.broadcastingStatusObs.subscribe((ev: BroadcastingStatusInfo) => {
|
this.broadcastingService.broadcastingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((ev: BroadcastingStatusInfo) => {
|
||||||
if (!!ev) {
|
if (!!ev) {
|
||||||
this.broadcastingStatus = ev.status;
|
this.broadcastingStatus = ev.status;
|
||||||
this.broadcastingId = ev.broadcastingId;
|
this.broadcastingId = ev.broadcastingId;
|
||||||
|
@ -733,85 +688,85 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToToolbarDirectives() {
|
private subscribeToToolbarDirectives() {
|
||||||
this.minimalSub = this.libService.minimal$.subscribe((value: boolean) => {
|
this.libService.minimal$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.isMinimal = value;
|
this.isMinimal = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.brandingLogoSub = this.libService.brandingLogo$.subscribe((value: string) => {
|
this.libService.brandingLogo$.pipe(takeUntil(this.destroy$)).subscribe((value: string) => {
|
||||||
this.brandingLogo = value;
|
this.brandingLogo = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.cameraButtonSub = this.libService.cameraButton$.subscribe((value: boolean) => {
|
this.libService.cameraButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showCameraButton = value;
|
this.showCameraButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.microphoneButtonSub = this.libService.microphoneButton$.subscribe((value: boolean) => {
|
this.libService.microphoneButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showMicrophoneButton = value;
|
this.showMicrophoneButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.screenshareButtonSub = this.libService.screenshareButton$.subscribe((value: boolean) => {
|
this.libService.screenshareButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showScreenshareButton = value && !this.platformService.isMobile();
|
this.showScreenshareButton = value && !this.platformService.isMobile();
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.fullscreenButtonSub = this.libService.fullscreenButton$.subscribe((value: boolean) => {
|
this.libService.fullscreenButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showFullscreenButton = value;
|
this.showFullscreenButton = value;
|
||||||
this.checkDisplayMoreOptions();
|
this.checkDisplayMoreOptions();
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.leaveButtonSub = this.libService.leaveButton$.subscribe((value: boolean) => {
|
this.libService.leaveButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showLeaveButton = value;
|
this.showLeaveButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.recordingButtonSub = this.libService.recordingButton$.subscribe((value: boolean) => {
|
this.libService.recordingButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showRecordingButton = value;
|
this.showRecordingButton = value;
|
||||||
this.checkDisplayMoreOptions();
|
this.checkDisplayMoreOptions();
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.broadcastingButtonSub = this.libService.broadcastingButton$.subscribe((value: boolean) => {
|
this.libService.broadcastingButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showBroadcastingButton = value;
|
this.showBroadcastingButton = value;
|
||||||
this.checkDisplayMoreOptions();
|
this.checkDisplayMoreOptions();
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settingsButtonSub = this.libService.toolbarSettingsButton$.subscribe((value: boolean) => {
|
this.libService.toolbarSettingsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showSettingsButton = value;
|
this.showSettingsButton = value;
|
||||||
this.checkDisplayMoreOptions();
|
this.checkDisplayMoreOptions();
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.chatPanelButtonSub = this.libService.chatPanelButton$.subscribe((value: boolean) => {
|
this.libService.chatPanelButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showChatPanelButton = value;
|
this.showChatPanelButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.participantsPanelButtonSub = this.libService.participantsPanelButton$.subscribe((value: boolean) => {
|
this.libService.participantsPanelButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showParticipantsPanelButton = value;
|
this.showParticipantsPanelButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.activitiesPanelButtonSub = this.libService.activitiesPanelButton$.subscribe((value: boolean) => {
|
this.libService.activitiesPanelButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showActivitiesPanelButton = value;
|
this.showActivitiesPanelButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.backgroundEffectsButtonSub = this.libService.backgroundEffectsButton$.subscribe((value: boolean) => {
|
this.libService.backgroundEffectsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showBackgroundEffectsButton = value;
|
this.showBackgroundEffectsButton = value;
|
||||||
this.checkDisplayMoreOptions();
|
this.checkDisplayMoreOptions();
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.displayLogoSub = this.libService.displayLogo$.subscribe((value: boolean) => {
|
this.libService.displayLogo$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showLogo = value;
|
this.showLogo = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.displayRoomNameSub = this.libService.displayRoomName$.subscribe((value: boolean) => {
|
this.libService.displayRoomName$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showSessionName = value;
|
this.showSessionName = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
this.captionsSubs = this.libService.captionsButton$.subscribe((value: boolean) => {
|
this.libService.captionsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showCaptionsButton = value;
|
this.showCaptionsButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.additionalButtonsPositionSub = this.libService.toolbarAdditionalButtonsPosition$.subscribe(
|
this.libService.toolbarAdditionalButtonsPosition$.pipe(takeUntil(this.destroy$)).subscribe(
|
||||||
(value: ToolbarAdditionalButtonsPosition) => {
|
(value: ToolbarAdditionalButtonsPosition) => {
|
||||||
// Using Promise.resolve() to defer change detection until the next microtask.
|
// Using Promise.resolve() to defer change detection until the next microtask.
|
||||||
// This ensures that Angular's change detection has the latest value before updating the view.
|
// This ensures that Angular's change detection has the latest value before updating the view.
|
||||||
|
@ -827,7 +782,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToCaptionsToggling() {
|
private subscribeToCaptionsToggling() {
|
||||||
this.captionsSubs = this.layoutService.captionsTogglingObs.subscribe((value: boolean) => {
|
this.layoutService.captionsTogglingObs.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.captionsEnabled = value;
|
this.captionsEnabled = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { animate, style, transition, trigger } from '@angular/animations';
|
import { animate, style, transition, trigger } from '@angular/animations';
|
||||||
import { AfterViewInit, Component, ContentChild, EventEmitter, OnDestroy, Output, TemplateRef, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, ContentChild, EventEmitter, OnDestroy, Output, TemplateRef, ViewChild } from '@angular/core';
|
||||||
import { Subscription, filter, skip, take } from 'rxjs';
|
import { Subject, filter, skip, take, takeUntil } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
ActivitiesPanelDirective,
|
ActivitiesPanelDirective,
|
||||||
AdditionalPanelsDirective,
|
AdditionalPanelsDirective,
|
||||||
|
@ -379,10 +379,8 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
_tokenError: any;
|
_tokenError: any;
|
||||||
private prejoinSub: Subscription;
|
|
||||||
private tokenSub: Subscription;
|
private destroy$ = new Subject<void>();
|
||||||
private tokenErrorSub: Subscription;
|
|
||||||
private participantNameSub: Subscription;
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private latestParticipantName: string | undefined;
|
private latestParticipantName: string | undefined;
|
||||||
|
|
||||||
|
@ -402,10 +400,8 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.prejoinSub) this.prejoinSub.unsubscribe();
|
this.destroy$.next();
|
||||||
if (this.participantNameSub) this.participantNameSub.unsubscribe();
|
this.destroy$.complete();
|
||||||
if (this.tokenSub) this.tokenSub.unsubscribe();
|
|
||||||
if (this.tokenErrorSub) this.tokenErrorSub.unsubscribe();
|
|
||||||
this.deviceSrv.clear();
|
this.deviceSrv.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,79 +595,91 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToVideconferenceDirectives() {
|
private subscribeToVideconferenceDirectives() {
|
||||||
this.tokenSub = this.libService.token$.pipe(skip(1)).subscribe((token: string) => {
|
this.libService.token$
|
||||||
try {
|
.pipe(
|
||||||
if (!token) {
|
skip(1),
|
||||||
this.log.e('Token is empty');
|
takeUntil(this.destroy$)
|
||||||
return;
|
)
|
||||||
}
|
.subscribe((token: string) => {
|
||||||
|
try {
|
||||||
|
if (!token) {
|
||||||
|
this.log.e('Token is empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const livekitUrl = this.libService.getLivekitUrl();
|
const livekitUrl = this.libService.getLivekitUrl();
|
||||||
this.openviduService.initializeAndSetToken(token, livekitUrl);
|
this.openviduService.initializeAndSetToken(token, livekitUrl);
|
||||||
this.log.d('Token has been successfully set. Room is ready to join');
|
this.log.d('Token has been successfully set. Room is ready to join');
|
||||||
this.isRoomReady = true;
|
this.isRoomReady = true;
|
||||||
this.showPrejoin = false;
|
this.showPrejoin = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log.e('Error trying to set token', error);
|
this.log.e('Error trying to set token', error);
|
||||||
|
this._tokenError = error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.tokenError$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((error: any) => {
|
||||||
|
if (!error) return;
|
||||||
|
|
||||||
|
this.log.e('Token error received', error);
|
||||||
this._tokenError = error;
|
this._tokenError = error;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tokenErrorSub = this.libService.tokenError$.subscribe((error: any) => {
|
if (!this.showPrejoin) {
|
||||||
if (!error) return;
|
this.actionService.openDialog(error.name, error.message, false);
|
||||||
|
|
||||||
this.log.e('Token error received', error);
|
|
||||||
this._tokenError = error;
|
|
||||||
|
|
||||||
if (!this.showPrejoin) {
|
|
||||||
this.actionService.openDialog(error.name, error.message, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.prejoinSub = this.libService.prejoin$.subscribe((value: boolean) => {
|
|
||||||
this.showPrejoin = value;
|
|
||||||
if (!this.showPrejoin) {
|
|
||||||
// Emit token ready if the prejoin page won't be shown
|
|
||||||
|
|
||||||
// Ensure we have a participant name before proceeding with the join
|
|
||||||
this.log.d('Prejoin page is hidden, checking participant name');
|
|
||||||
// Check if we have a participant name already
|
|
||||||
if (this.latestParticipantName) {
|
|
||||||
// We have a name, proceed immediately
|
|
||||||
this._onReadyToJoin();
|
|
||||||
} else {
|
|
||||||
// No name yet - set up a one-time subscription to wait for it
|
|
||||||
const waitForNameSub = this.libService.participantName$
|
|
||||||
.pipe(
|
|
||||||
filter((name) => !!name),
|
|
||||||
take(1)
|
|
||||||
)
|
|
||||||
.subscribe(() => {
|
|
||||||
// Now we have the name in latestParticipantName
|
|
||||||
this._onReadyToJoin();
|
|
||||||
});
|
|
||||||
// Add safety timeout in case name never arrives
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!this.latestParticipantName) {
|
|
||||||
this.log.w('No participant name received after timeout, proceeding anyway');
|
|
||||||
waitForNameSub.unsubscribe();
|
|
||||||
const storedName = this.storageSrv.getParticipantName();
|
|
||||||
if (storedName) {
|
|
||||||
this.latestParticipantName = storedName;
|
|
||||||
this.libService.setParticipantName(storedName);
|
|
||||||
}
|
|
||||||
this._onReadyToJoin();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
// this.cd.markForCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.participantNameSub = this.libService.participantName$.subscribe((name: string) => {
|
this.libService.prejoin$
|
||||||
if (name) {
|
.pipe(takeUntil(this.destroy$))
|
||||||
this.latestParticipantName = name;
|
.subscribe((value: boolean) => {
|
||||||
this.storageSrv.setParticipantName(name);
|
this.showPrejoin = value;
|
||||||
}
|
if (!this.showPrejoin) {
|
||||||
});
|
// Emit token ready if the prejoin page won't be shown
|
||||||
|
|
||||||
|
// Ensure we have a participant name before proceeding with the join
|
||||||
|
this.log.d('Prejoin page is hidden, checking participant name');
|
||||||
|
// Check if we have a participant name already
|
||||||
|
if (this.latestParticipantName) {
|
||||||
|
// We have a name, proceed immediately
|
||||||
|
this._onReadyToJoin();
|
||||||
|
} else {
|
||||||
|
// No name yet - set up a one-time subscription to wait for it
|
||||||
|
this.libService.participantName$
|
||||||
|
.pipe(
|
||||||
|
filter((name) => !!name),
|
||||||
|
take(1),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
)
|
||||||
|
.subscribe(() => {
|
||||||
|
// Now we have the name in latestParticipantName
|
||||||
|
this._onReadyToJoin();
|
||||||
|
});
|
||||||
|
// Add safety timeout in case name never arrives
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.latestParticipantName) {
|
||||||
|
this.log.w('No participant name received after timeout, proceeding anyway');
|
||||||
|
const storedName = this.storageSrv.getParticipantName();
|
||||||
|
if (storedName) {
|
||||||
|
this.latestParticipantName = storedName;
|
||||||
|
this.libService.setParticipantName(storedName);
|
||||||
|
}
|
||||||
|
this._onReadyToJoin();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.participantName$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((name: string) => {
|
||||||
|
if (name) {
|
||||||
|
this.latestParticipantName = name;
|
||||||
|
this.storageSrv.setParticipantName(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue