mirror of https://github.com/OpenVidu/openvidu.git
openvidu-components: Added virtual background and recording features
Added background effects GUI WIP: Added activities panelpull/722/head
parent
1655335aa7
commit
570709adc2
|
@ -0,0 +1,79 @@
|
||||||
|
#activities-container {
|
||||||
|
margin: 20px;
|
||||||
|
background-color: var(--ov-panel-background);
|
||||||
|
border-radius: var(--ov-panel-radius);
|
||||||
|
max-height: calc(100% - 40px);
|
||||||
|
min-height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container h3 {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container button {
|
||||||
|
margin-left: auto;
|
||||||
|
border-radius: var(--ov-buttons-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.activities-body-container {
|
||||||
|
display: block !important;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon {
|
||||||
|
display: inherit;
|
||||||
|
background-color: var(--ov-light-color);
|
||||||
|
border-radius: var(--ov-panel-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon mat-icon {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.activity-subtitle {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 11px !important;
|
||||||
|
}
|
||||||
|
.activity-title {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-action-buttons{
|
||||||
|
align-self: flex-start;
|
||||||
|
margin-top: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-list-text {
|
||||||
|
padding-left: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-expansion-panel-header {
|
||||||
|
padding: 0px 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-list-base .mat-list-item .mat-list-item-content, .mat-list-base .mat-list-option .mat-list-item-content {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep mat-expansion-panel .mat-expansion-panel-body {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
::ng-deep .mat-expansion-panel-header-description {
|
||||||
|
flex-grow: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-expansion-panel {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<div class="panel" id="activities-container" fxLayout="column" fxLayoutAlign="space-evenly none">
|
||||||
|
<div class="header-container" fxFlex="55px" fxLayoutAlign="start center">
|
||||||
|
<h3>Activities</h3>
|
||||||
|
<button mat-icon-button matTooltip="Close" (click)="close()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="activities-body-container" fxFlex="75%" fxLayoutAlign="space-evenly none">
|
||||||
|
<mat-accordion>
|
||||||
|
<ov-recording-activity></ov-recording-activity>
|
||||||
|
</mat-accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ActivitiesPanelComponent } from './activities-panel.component';
|
||||||
|
|
||||||
|
describe('ActivitiesPanelComponent', () => {
|
||||||
|
let component: ActivitiesPanelComponent;
|
||||||
|
let fixture: ComponentFixture<ActivitiesPanelComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ActivitiesPanelComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ActivitiesPanelComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { PanelType } from '../../../models/panel.model';
|
||||||
|
import { PanelService } from '../../../services/panel/panel.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ov-activities-panel',
|
||||||
|
templateUrl: './activities-panel.component.html',
|
||||||
|
styleUrls: ['./activities-panel.component.css']
|
||||||
|
})
|
||||||
|
export class ActivitiesPanelComponent implements OnInit {
|
||||||
|
constructor(private panelService: PanelService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
ngOnDestroy() {}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.panelService.togglePanel(PanelType.ACTIVITIES);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#recording-status {
|
||||||
|
color: var(--ov-text-color);
|
||||||
|
display: inline;
|
||||||
|
padding: 3px;
|
||||||
|
font-size: 11px;
|
||||||
|
border-radius: var(--ov-panel-radius);
|
||||||
|
}
|
||||||
|
.started {
|
||||||
|
background-color: #005704;
|
||||||
|
}
|
||||||
|
.stopped {
|
||||||
|
background-color: var(--ov-light-color);
|
||||||
|
color: var(--ov-panel-text-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#recording-file-item {
|
||||||
|
padding: 0px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recording-action-buttons{
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#start-recording-btn {
|
||||||
|
background-color: var(--ov-tertiary-color);
|
||||||
|
color: var(--ov-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#stop-recording-btn {
|
||||||
|
background-color: var(--ov-warn-color);
|
||||||
|
color: var(--ov-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-expansion-panel {
|
||||||
|
margin: 0pc 0px 15px 0px;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
<mat-expansion-panel (opened)="panelOpened()" (closed)="panelClosed()">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-list>
|
||||||
|
<mat-list-item>
|
||||||
|
<div matListAvatar class="activity-icon">
|
||||||
|
<mat-icon >video_camera_front</mat-icon>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<h3 matLine class="activity-title">Recording</h3>
|
||||||
|
<p matLine class="activity-subtitle">Record your meeting for posterity</p>
|
||||||
|
<div class="activity-action-buttons">
|
||||||
|
<div
|
||||||
|
id="recording-status"
|
||||||
|
[ngClass]="{
|
||||||
|
started: recordingStatus === recStatusEnum.STARTED,
|
||||||
|
stopped: recordingStatus === recStatusEnum.STOPPED
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span>{{ recordingStatus }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div *ngIf="opened">
|
||||||
|
<mat-list *ngIf="isSessionCreator" id="recording-file-item">
|
||||||
|
<mat-list-item>
|
||||||
|
<mat-icon *ngIf="recording" matListAvatar class="participant-avatar"> video_file </mat-icon>
|
||||||
|
<h3 *ngIf="recording" matLine class="participant-nickname">{{ recording.name }}</h3>
|
||||||
|
<p *ngIf="recording" matLine class="participant-subtitle">
|
||||||
|
{{ recording.id }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="recording-action-buttons">
|
||||||
|
<button
|
||||||
|
*ngIf="recording"
|
||||||
|
mat-stroked-button
|
||||||
|
id="stop-recording-btn"
|
||||||
|
matTooltip="Stop recording"
|
||||||
|
(click)="stopRecording()"
|
||||||
|
>
|
||||||
|
Stop recording
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
*ngIf="recordingStatus === recStatusEnum.STOPPED"
|
||||||
|
mat-stroked-button
|
||||||
|
id="start-recording-btn"
|
||||||
|
matTooltip="Start recording"
|
||||||
|
(click)="startRecording()"
|
||||||
|
>
|
||||||
|
Start recording
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-list-item>
|
||||||
|
<hr />
|
||||||
|
</mat-list>
|
||||||
|
|
||||||
|
<!-- Visalizador de recordings -->
|
||||||
|
<div>NO RECORDINGS FOUND</div>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RecordingActivityComponent } from './recording-activity.component';
|
||||||
|
|
||||||
|
describe('RecordingActivityComponent', () => {
|
||||||
|
let component: RecordingActivityComponent;
|
||||||
|
let fixture: ComponentFixture<RecordingActivityComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ RecordingActivityComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(RecordingActivityComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
import { RecordingStatus } from '../../../../models/recording.model';
|
||||||
|
import { RecordingService, RecordingInfo } from '../../../../services/recording/recording.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ov-recording-activity',
|
||||||
|
templateUrl: './recording-activity.component.html',
|
||||||
|
styleUrls: ['./recording-activity.component.css', '../activities-panel.component.css']
|
||||||
|
})
|
||||||
|
export class RecordingActivityComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides event notifications that fire when start recording button has been clicked.
|
||||||
|
*/
|
||||||
|
@Output() startRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides event notifications that fire when stop recording button has been clicked.
|
||||||
|
*/
|
||||||
|
@Output() stopRecordingClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
||||||
|
recStatusEnum = RecordingStatus;
|
||||||
|
isSessionCreator = true;
|
||||||
|
recording: RecordingInfo;
|
||||||
|
recordingSubscription: Subscription;
|
||||||
|
|
||||||
|
opened: boolean = false;
|
||||||
|
|
||||||
|
constructor(private recordingService: RecordingService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.subscribeToRecordingStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.recordingSubscription) this.recordingSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
panelOpened() {
|
||||||
|
//TODO EMITIR EVENTO
|
||||||
|
this.opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
panelClosed() {
|
||||||
|
//TODO EMITIR EVENTO
|
||||||
|
this.opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
startRecording() {
|
||||||
|
console.log('START RECORDING');
|
||||||
|
this.startRecordingClicked.emit();
|
||||||
|
//TODO: REMOVE
|
||||||
|
const info: RecordingInfo = {
|
||||||
|
status: RecordingStatus.STARTED,
|
||||||
|
id: '1',
|
||||||
|
name: 'akajo',
|
||||||
|
reason: null
|
||||||
|
};
|
||||||
|
this.recordingService.startRecording(<any>info);
|
||||||
|
}
|
||||||
|
stopRecording() {
|
||||||
|
console.log('STOP RECORDING');
|
||||||
|
this.stopRecordingClicked.emit();
|
||||||
|
//TODO: REMOVE
|
||||||
|
const info: RecordingInfo = {
|
||||||
|
status: RecordingStatus.STOPPED,
|
||||||
|
id: '1',
|
||||||
|
name: 'akajo',
|
||||||
|
reason: 'lalal'
|
||||||
|
};
|
||||||
|
this.recordingService.stopRecording(<any>info);
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeToRecordingStatus() {
|
||||||
|
this.recordingSubscription = this.recordingService.recordingStatusObs.subscribe((info: RecordingInfo) => {
|
||||||
|
if (info) {
|
||||||
|
this.recordingStatus = info.status;
|
||||||
|
if (info.status === RecordingStatus.STARTED) {
|
||||||
|
this.recording = info;
|
||||||
|
} else {
|
||||||
|
this.recording = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#background-effects-container {
|
||||||
|
margin: 20px;
|
||||||
|
background-color: var(--ov-panel-background);
|
||||||
|
border-radius: var(--ov-panel-radius);
|
||||||
|
max-height: calc(100% - 40px);
|
||||||
|
min-height: calc(100% - 40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container h3 {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-container button {
|
||||||
|
margin-left: auto;
|
||||||
|
border-radius: var(--ov-buttons-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.effects-container {
|
||||||
|
display: block !important;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.effect-button {
|
||||||
|
margin: 5px;
|
||||||
|
border-radius: var(--ov-panel-radius);
|
||||||
|
background-color: var(--ov-light-color);
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-effect-btn {
|
||||||
|
border: 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hard-blur-btn .mat-icon {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
<div class="panel" id="background-effects-container" fxLayout="column" fxLayoutAlign="space-evenly none">
|
||||||
|
<div class="header-container" fxFlex="55px" fxLayoutAlign="start center">
|
||||||
|
<h3>Background effects</h3>
|
||||||
|
<button mat-icon-button matTooltip="Close" (click)="close()">
|
||||||
|
<mat-icon>close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="effects-container" fxFlex="100%" fxLayoutAlign="space-evenly none">
|
||||||
|
<div>
|
||||||
|
<h4>Blurred background</h4>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
class="effect-button"
|
||||||
|
[class.active-effect-btn]="effectActive === 'no_effect'"
|
||||||
|
(click)="effectActive = 'no_effect'"
|
||||||
|
>
|
||||||
|
<mat-icon matTooltip="No background effect">block</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
class="effect-button"
|
||||||
|
[class.active-effect-btn]="effectActive === 'soft_blur'"
|
||||||
|
(click)="effectActive = 'soft_blur'"
|
||||||
|
>
|
||||||
|
<mat-icon matTooltip="Soft blur effect">blur_on</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
class="effect-button"
|
||||||
|
id="hard-blur-btn"
|
||||||
|
[class.active-effect-btn]="effectActive === 'hard_blur'"
|
||||||
|
(click)="effectActive = 'hard_blur'"
|
||||||
|
>
|
||||||
|
<mat-icon matTooltip="Hard blur effect">blur_on</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
<h4>Background images</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { BackgroundEffectsPanelComponent } from './background-effects-panel.component';
|
||||||
|
|
||||||
|
describe('BackgroundEffectsPanelComponent', () => {
|
||||||
|
let component: BackgroundEffectsPanelComponent;
|
||||||
|
let fixture: ComponentFixture<BackgroundEffectsPanelComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ BackgroundEffectsPanelComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BackgroundEffectsPanelComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
|
import { PanelType } from '../../../models/panel.model';
|
||||||
|
import { PanelService } from '../../../services/panel/panel.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ov-background-effects-panel',
|
||||||
|
templateUrl: './background-effects-panel.component.html',
|
||||||
|
styleUrls: ['./background-effects-panel.component.css'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class BackgroundEffectsPanelComponent implements OnInit {
|
||||||
|
|
||||||
|
effectActive: string;
|
||||||
|
|
||||||
|
constructor(private panelService: PanelService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,9 +9,19 @@
|
||||||
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="participantsPanelTemplate"></ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Background effects panel -->
|
||||||
|
<ng-container *ngIf="isBackgroundEffectsPanelOpened">
|
||||||
|
<ng-container *ngTemplateOutlet="backgroundEffectsPanelTemplate"></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Activities panel -->
|
||||||
|
<ng-container *ngIf="isActivitiesPanelOpened">
|
||||||
|
<ng-container *ngTemplateOutlet="activitiesPanelTemplate"></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
<!-- <ov-activities-panel *ngIf="isActivitiesPanelOpened"></ov-activities-panel> -->
|
||||||
|
|
||||||
|
|
||||||
<!-- External additional panels -->
|
<!-- External additional panels -->
|
||||||
<ng-container *ngIf="additionalPanelsTemplate && isExternalPanelOpened">
|
<ng-container *ngIf="additionalPanelsTemplate && isExternalPanelOpened">
|
||||||
<ng-container *ngTemplateOutlet="additionalPanelsTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="additionalPanelsTemplate"></ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core';
|
||||||
import { skip, Subscription } from 'rxjs';
|
import { skip, Subscription } from 'rxjs';
|
||||||
import { ChatPanelDirective, AdditionalPanelsDirective, ParticipantsPanelDirective } from '../../directives/template/openvidu-angular.directive';
|
import {
|
||||||
|
ChatPanelDirective,
|
||||||
|
AdditionalPanelsDirective,
|
||||||
|
ParticipantsPanelDirective,
|
||||||
|
BackgroundEffectsPanelDirective,
|
||||||
|
ActivitiesPanelDirective
|
||||||
|
} from '../../directives/template/openvidu-angular.directive';
|
||||||
import { PanelType } from '../../models/panel.model';
|
import { PanelType } from '../../models/panel.model';
|
||||||
import { PanelService } from '../../services/panel/panel.service';
|
import { PanelService } from '../../services/panel/panel.service';
|
||||||
|
|
||||||
|
@ -53,6 +59,15 @@ export class PanelComponent implements OnInit {
|
||||||
*/
|
*/
|
||||||
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>;
|
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@ContentChild('backgroundEffectsPanel', { read: TemplateRef }) backgroundEffectsPanelTemplate: TemplateRef<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@ContentChild('activitiesPanel', { read: TemplateRef }) activitiesPanelTemplate: TemplateRef<any>;
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -72,6 +87,24 @@ export class PanelComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ContentChild(BackgroundEffectsPanelDirective)
|
||||||
|
set externalBackgroundEffectsPanel(externalBackgroundEffectsPanel: BackgroundEffectsPanelDirective) {
|
||||||
|
// This directive will has value only when BACKGROUND EFFECTS PANEL component tagged with '*ovBackgroundEffectsPanel'
|
||||||
|
// is inside of the PANEL component tagged with '*ovPanel'
|
||||||
|
if (externalBackgroundEffectsPanel) {
|
||||||
|
this.backgroundEffectsPanelTemplate = externalBackgroundEffectsPanel.template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ContentChild(ActivitiesPanelDirective)
|
||||||
|
set externalActivitiesPanel(externalActivitiesPanel: ActivitiesPanelDirective) {
|
||||||
|
// This directive will has value only when ACTIVITIES PANEL component tagged with '*ovActivitiesPanel'
|
||||||
|
// is inside of the PANEL component tagged with '*ovPanel'
|
||||||
|
if (externalActivitiesPanel) {
|
||||||
|
this.activitiesPanelTemplate = externalActivitiesPanel.template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ContentChild(ChatPanelDirective)
|
@ContentChild(ChatPanelDirective)
|
||||||
set externalChatPanel(externalChatPanel: ChatPanelDirective) {
|
set externalChatPanel(externalChatPanel: ChatPanelDirective) {
|
||||||
// This directive will has value only when CHAT PANEL component tagged with '*ovChatPanel'
|
// This directive will has value only when CHAT PANEL component tagged with '*ovChatPanel'
|
||||||
|
@ -92,6 +125,8 @@ export class PanelComponent implements OnInit {
|
||||||
|
|
||||||
isParticipantsPanelOpened: boolean;
|
isParticipantsPanelOpened: boolean;
|
||||||
isChatPanelOpened: boolean;
|
isChatPanelOpened: boolean;
|
||||||
|
isBackgroundEffectsPanelOpened: boolean;
|
||||||
|
isActivitiesPanelOpened: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -115,9 +150,13 @@ export class PanelComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToPanelToggling() {
|
private subscribeToPanelToggling() {
|
||||||
this.panelSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: { opened: boolean; type?: PanelType | string }) => {
|
this.panelSubscription = this.panelService.panelOpenedObs
|
||||||
|
.pipe(skip(1))
|
||||||
|
.subscribe((ev: { opened: boolean; type?: PanelType | string }) => {
|
||||||
this.isChatPanelOpened = ev.opened && ev.type === PanelType.CHAT;
|
this.isChatPanelOpened = ev.opened && ev.type === PanelType.CHAT;
|
||||||
this.isParticipantsPanelOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
this.isParticipantsPanelOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
||||||
|
this.isBackgroundEffectsPanelOpened = ev.opened && ev.type === PanelType.BACKGROUND_EFFECTS;
|
||||||
|
this.isActivitiesPanelOpened = ev.opened && ev.type === PanelType.ACTIVITIES;
|
||||||
this.isExternalPanelOpened = ev.opened && ev.type !== PanelType.PARTICIPANTS && ev.type !== PanelType.CHAT;
|
this.isExternalPanelOpened = ev.opened && ev.type !== PanelType.PARTICIPANTS && ev.type !== PanelType.CHAT;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,11 +16,28 @@ hr {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ov-layout {
|
#prejoin-container ::ng-deep .sidenav-container {
|
||||||
height: -webkit-fill-available;
|
padding-top: 0px !important;
|
||||||
height: -moz-available;
|
}
|
||||||
width: -webkit-fill-available;
|
#prejoin-container ::ng-deep #background-effects-container {
|
||||||
width: -moz-available;
|
margin: 0px !important;
|
||||||
|
max-height: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prejoin-container ::ng-deep .mat-drawer-container, #prejoin-container ::ng-deep .sidenav-menu {
|
||||||
|
background-color: var(--ov-light-color) !important;
|
||||||
|
}
|
||||||
|
#prejoin-container ::ng-deep .sidenav-menu {
|
||||||
|
width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#background-effects-btn {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: var(--ov-secondary-color);
|
||||||
|
bottom: 5px;
|
||||||
|
right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-panel {
|
.media-panel {
|
||||||
|
|
|
@ -1,10 +1,30 @@
|
||||||
<div class="container" id="prejoin-container" fxLayout.gt-sm="row" fxLayout.lt-md="column">
|
<div class="container" id="prejoin-container" fxLayout.gt-sm="row" fxLayout.lt-md="column">
|
||||||
<div fxFlex.gt-sm="65%" fxFlex.lt-md="55%" fxLayoutAlign="center center" id="layout-container">
|
<div fxFlex.gt-sm="65%" fxFlex.lt-md="55%" fxLayoutAlign="center center" id="layout-container">
|
||||||
|
<ov-session [usedInPrejoinPage]="true">
|
||||||
|
<ng-template #panel *ngIf="!isMinimal && showBackgroundEffectsButton">
|
||||||
|
<ov-panel>
|
||||||
|
<ng-template #backgroundEffectsPanel>
|
||||||
|
<ov-background-effects-panel></ov-background-effects-panel>
|
||||||
|
</ng-template>
|
||||||
|
</ov-panel>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #layout>
|
||||||
<ov-layout>
|
<ov-layout>
|
||||||
<ng-template #stream let-stream>
|
<ng-template #stream let-stream>
|
||||||
|
<button
|
||||||
|
*ngIf="!isMinimal && !isOpenViduCE && showBackgroundEffectsButton"
|
||||||
|
mat-icon-button
|
||||||
|
id="background-effects-btn"
|
||||||
|
(click)="toggleBackgroundEffects()"
|
||||||
|
>
|
||||||
|
<mat-icon>auto_awesome</mat-icon>
|
||||||
|
</button>
|
||||||
<ov-stream [stream]="stream" [displayParticipantName]="false" [settingsButton]="false"></ov-stream>
|
<ov-stream [stream]="stream" [displayParticipantName]="false" [settingsButton]="false"></ov-stream>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ov-layout>
|
</ov-layout>
|
||||||
|
</ng-template>
|
||||||
|
</ov-session>
|
||||||
</div>
|
</div>
|
||||||
<div fxFlex.gt-sm="35%" fxFlex.lt-md="45%" fxLayoutAlign="center center" class="media-panel" *ngIf="localParticipant">
|
<div fxFlex.gt-sm="35%" fxFlex.lt-md="45%" fxLayoutAlign="center center" class="media-panel" *ngIf="localParticipant">
|
||||||
<div fxLayout="column" fxLayoutGap="10px" class="media-panel-container">
|
<div fxLayout="column" fxLayoutGap="10px" class="media-panel-container">
|
||||||
|
@ -18,7 +38,14 @@
|
||||||
</button>
|
</button>
|
||||||
<mat-form-field appearance="standard">
|
<mat-form-field appearance="standard">
|
||||||
<mat-label>Nickname</mat-label>
|
<mat-label>Nickname</mat-label>
|
||||||
<input matInput type="text" maxlength="20" [(ngModel)]="nickname" (change)="updateNickname()" autocomplete="off" />
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
maxlength="20"
|
||||||
|
[(ngModel)]="nickname"
|
||||||
|
(change)="updateNickname()"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<!-- <mat-button-toggle-group style="border-radius: 20px">
|
<!-- <mat-button-toggle-group style="border-radius: 20px">
|
||||||
|
@ -54,7 +81,11 @@
|
||||||
</button>
|
</button>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Video devices</mat-label>
|
<mat-label>Video devices</mat-label>
|
||||||
<mat-select [disabled]="isVideoMuted || !hasVideoDevices" [value]="cameraSelected?.device" (selectionChange)="onCameraSelected($event)">
|
<mat-select
|
||||||
|
[disabled]="isVideoMuted || !hasVideoDevices"
|
||||||
|
[value]="cameraSelected?.device"
|
||||||
|
(selectionChange)="onCameraSelected($event)"
|
||||||
|
>
|
||||||
<mat-option *ngFor="let camera of cameras" [value]="camera.device">
|
<mat-option *ngFor="let camera of cameras" [value]="camera.device">
|
||||||
{{ camera.label }}
|
{{ camera.label }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
|
@ -76,7 +107,11 @@
|
||||||
</button>
|
</button>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Audio devices</mat-label>
|
<mat-label>Audio devices</mat-label>
|
||||||
<mat-select [disabled]="isAudioMuted || !hasAudioDevices" [value]="microphoneSelected?.device" (selectionChange)="onMicrophoneSelected($event)">
|
<mat-select
|
||||||
|
[disabled]="isAudioMuted || !hasAudioDevices"
|
||||||
|
[value]="microphoneSelected?.device"
|
||||||
|
(selectionChange)="onMicrophoneSelected($event)"
|
||||||
|
>
|
||||||
<mat-option *ngFor="let microphone of microphones" [value]="microphone.device">
|
<mat-option *ngFor="let microphone of microphones" [value]="microphone.device">
|
||||||
{{ microphone.label }}
|
{{ microphone.label }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
import { Component, HostListener, OnDestroy, OnInit, Output, EventEmitter } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
HostListener,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
EventEmitter
|
||||||
|
} from '@angular/core';
|
||||||
import { PublisherProperties } from 'openvidu-browser';
|
import { PublisherProperties } from 'openvidu-browser';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { CustomDevice } from '../../models/device.model';
|
import { CustomDevice } from '../../models/device.model';
|
||||||
import { ILogger } from '../../models/logger.model';
|
import { ILogger } from '../../models/logger.model';
|
||||||
|
import { PanelType } from '../../models/panel.model';
|
||||||
import { ParticipantAbstractModel } from '../../models/participant.model';
|
import { ParticipantAbstractModel } from '../../models/participant.model';
|
||||||
|
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
||||||
import { DeviceService } from '../../services/device/device.service';
|
import { DeviceService } from '../../services/device/device.service';
|
||||||
import { LayoutService } from '../../services/layout/layout.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 { PanelService } from '../../services/panel/panel.service';
|
||||||
import { ParticipantService } from '../../services/participant/participant.service';
|
import { ParticipantService } from '../../services/participant/participant.service';
|
||||||
import { StorageService } from '../../services/storage/storage.service';
|
import { StorageService } from '../../services/storage/storage.service';
|
||||||
|
|
||||||
|
@ -33,9 +43,21 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
hasAudioDevices: boolean;
|
hasAudioDevices: boolean;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
nickname: string;
|
nickname: string;
|
||||||
|
isOpenViduCE: boolean;
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
showBackgroundEffectsButton: boolean = true;
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
isMinimal: boolean = false;
|
||||||
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private localParticipantSubscription: Subscription;
|
private localParticipantSubscription: Subscription;
|
||||||
private screenShareStateSubscription: Subscription;
|
private screenShareStateSubscription: Subscription;
|
||||||
|
private minimalSub: Subscription;
|
||||||
|
private backgroundEffectsButtonSub: Subscription;
|
||||||
|
|
||||||
@HostListener('window:resize')
|
@HostListener('window:resize')
|
||||||
sizeChange() {
|
sizeChange() {
|
||||||
|
@ -49,13 +71,17 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
private loggerSrv: LoggerService,
|
private loggerSrv: LoggerService,
|
||||||
private openviduService: OpenViduService,
|
private openviduService: OpenViduService,
|
||||||
private participantService: ParticipantService,
|
private participantService: ParticipantService,
|
||||||
|
protected panelService: PanelService,
|
||||||
|
private libService: OpenViduAngularConfigService,
|
||||||
private storageSrv: StorageService
|
private storageSrv: StorageService
|
||||||
) {
|
) {
|
||||||
this.log = this.loggerSrv.get('PreJoinComponent');
|
this.log = this.loggerSrv.get('PreJoinComponent');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.subscribeToPrejoinDirectives();
|
||||||
this.subscribeToLocalParticipantEvents();
|
this.subscribeToLocalParticipantEvents();
|
||||||
|
this.isOpenViduCE = this.openviduService.isOpenViduCE();
|
||||||
|
|
||||||
this.windowSize = window.innerWidth;
|
this.windowSize = window.innerWidth;
|
||||||
this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable();
|
this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable();
|
||||||
|
@ -79,6 +105,9 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
if (this.screenShareStateSubscription) {
|
if (this.screenShareStateSubscription) {
|
||||||
this.screenShareStateSubscription.unsubscribe();
|
this.screenShareStateSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.backgroundEffectsButtonSub) this.backgroundEffectsButtonSub.unsubscribe();
|
||||||
|
if (this.minimalSub) this.minimalSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
async onCameraSelected(event: any) {
|
async onCameraSelected(event: any) {
|
||||||
|
@ -138,6 +167,10 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
this.onJoinButtonClicked.emit();
|
this.onJoinButtonClicked.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleBackgroundEffects() {
|
||||||
|
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
|
||||||
|
}
|
||||||
|
|
||||||
private subscribeToLocalParticipantEvents() {
|
private subscribeToLocalParticipantEvents() {
|
||||||
this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p) => {
|
this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p) => {
|
||||||
this.localParticipant = p;
|
this.localParticipant = p;
|
||||||
|
@ -145,6 +178,17 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private subscribeToPrejoinDirectives() {
|
||||||
|
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
|
||||||
|
this.isMinimal = value;
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
this.backgroundEffectsButtonSub = this.libService.backgroundEffectsButton.subscribe((value: boolean) => {
|
||||||
|
this.showBackgroundEffectsButton = value;
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//? After test in Chrome and Firefox, the devices always have labels.
|
//? After test in Chrome and Firefox, the devices always have labels.
|
||||||
//? It's not longer needed
|
//? It's not longer needed
|
||||||
// private handlePublisherSuccess(publisher: Publisher) {
|
// private handlePublisherSuccess(publisher: Publisher) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div id="session-container">
|
<div id="session-container">
|
||||||
<mat-sidenav-container class="sidenav-container">
|
<mat-sidenav-container #videoContainer class="sidenav-container">
|
||||||
<mat-sidenav
|
<mat-sidenav
|
||||||
#sidenav
|
#sidenav
|
||||||
mode="{{ sidenavMode }}"
|
mode="{{ sidenavMode }}"
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
</mat-sidenav-content>
|
</mat-sidenav-content>
|
||||||
</mat-sidenav-container>
|
</mat-sidenav-container>
|
||||||
|
|
||||||
<div id="footer-container">
|
<div id="footer-container" *ngIf="toolbarTemplate">
|
||||||
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,14 +2,16 @@ import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
ContentChild,
|
ContentChild,
|
||||||
|
ElementRef,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
HostListener,
|
HostListener,
|
||||||
|
Input,
|
||||||
OnInit,
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Subscriber, Session, StreamEvent, StreamPropertyChangedEvent, SessionDisconnectedEvent, ConnectionEvent } from 'openvidu-browser';
|
import { Subscriber, Session, StreamEvent, StreamPropertyChangedEvent, SessionDisconnectedEvent, ConnectionEvent, RecordingEvent } from 'openvidu-browser';
|
||||||
|
|
||||||
import { VideoType } from '../../models/video-type.model';
|
import { VideoType } from '../../models/video-type.model';
|
||||||
import { ILogger } from '../../models/logger.model';
|
import { ILogger } from '../../models/logger.model';
|
||||||
|
@ -27,7 +29,7 @@ import { LayoutService } from '../../services/layout/layout.service';
|
||||||
import { Subscription, skip } from 'rxjs';
|
import { Subscription, skip } from 'rxjs';
|
||||||
import { PanelType } from '../../models/panel.model';
|
import { PanelType } from '../../models/panel.model';
|
||||||
import { PanelService } from '../../services/panel/panel.service';
|
import { PanelService } from '../../services/panel/panel.service';
|
||||||
import { PlatformService } from '../../services/platform/platform.service';
|
import { RecordingService } from '../../services/recording/recording.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -44,6 +46,7 @@ export class SessionComponent implements OnInit {
|
||||||
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>;
|
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>;
|
||||||
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
|
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
|
||||||
|
|
||||||
|
@Input() usedInPrejoinPage = false;
|
||||||
@Output() onSessionCreated = new EventEmitter<any>();
|
@Output() onSessionCreated = new EventEmitter<any>();
|
||||||
|
|
||||||
session: Session;
|
session: Session;
|
||||||
|
@ -69,7 +72,8 @@ export class SessionComponent implements OnInit {
|
||||||
protected chatService: ChatService,
|
protected chatService: ChatService,
|
||||||
protected tokenService: TokenService,
|
protected tokenService: TokenService,
|
||||||
protected layoutService: LayoutService,
|
protected layoutService: LayoutService,
|
||||||
protected panelService: PanelService
|
protected panelService: PanelService,
|
||||||
|
private recordingService: RecordingService
|
||||||
) {
|
) {
|
||||||
this.log = this.loggerSrv.get('SessionComponent');
|
this.log = this.loggerSrv.get('SessionComponent');
|
||||||
}
|
}
|
||||||
|
@ -94,7 +98,19 @@ export class SessionComponent implements OnInit {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewChild('videoContainer', {static:false, read: ElementRef })
|
||||||
|
set videoContainer(container: ElementRef) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (container && !this.toolbarTemplate) {
|
||||||
|
container.nativeElement.style.height = '100%';
|
||||||
|
container.nativeElement.style.minHeight = '100%';
|
||||||
|
this.layoutService.update();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
if(!this.usedInPrejoinPage){
|
||||||
this.session = this.openviduService.getWebcamSession();
|
this.session = this.openviduService.getWebcamSession();
|
||||||
this.sessionScreen = this.openviduService.getScreenSession();
|
this.sessionScreen = this.openviduService.getScreenSession();
|
||||||
this.subscribeToConnectionCreatedAndDestroyed();
|
this.subscribeToConnectionCreatedAndDestroyed();
|
||||||
|
@ -104,6 +120,9 @@ export class SessionComponent implements OnInit {
|
||||||
this.subscribeToNicknameChanged();
|
this.subscribeToNicknameChanged();
|
||||||
this.chatService.subscribeToChat();
|
this.chatService.subscribeToChat();
|
||||||
this.subscribeToReconnection();
|
this.subscribeToReconnection();
|
||||||
|
// if(RecordingEnabled){
|
||||||
|
this.subscribeToRecordingEvents();
|
||||||
|
// }
|
||||||
this.onSessionCreated.emit(this.session);
|
this.onSessionCreated.emit(this.session);
|
||||||
|
|
||||||
await this.connectToSession();
|
await this.connectToSession();
|
||||||
|
@ -113,6 +132,7 @@ export class SessionComponent implements OnInit {
|
||||||
// this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), false);
|
// this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), false);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
// Reconnecting session is received in Firefox
|
// Reconnecting session is received in Firefox
|
||||||
|
@ -270,4 +290,14 @@ export class SessionComponent implements OnInit {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private subscribeToRecordingEvents() {
|
||||||
|
this.session.on('recordingStarted', (event: RecordingEvent) => {
|
||||||
|
this.recordingService.startRecording(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.session.on('recordingStopped', (event: RecordingEvent) => {
|
||||||
|
this.recordingService.stopRecording(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,6 @@
|
||||||
top: 40px;
|
top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-error {
|
|
||||||
text-align: center;
|
|
||||||
color: #353535;
|
|
||||||
}
|
|
||||||
|
|
||||||
video {
|
video {
|
||||||
-o-object-fit: cover;
|
-o-object-fit: cover;
|
||||||
|
@ -115,17 +111,6 @@
|
||||||
border-radius: var(--ov-video-radius);
|
border-radius: var(--ov-video-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-error,
|
|
||||||
::ng-deep .mat-focused .mat-form-field-label,
|
|
||||||
::ng-deep .mat-form-field-appearance-legacy .mat-form-field-label {
|
|
||||||
color: #cacaca !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
::ng-deep .mat-form-field-appearance-legacy .mat-form-field-underline,
|
|
||||||
::ng-deep .mat-form-field.mat-focused .mat-form-field-ripple {
|
|
||||||
background-color: #cacaca !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
input {
|
||||||
caret-color: #ffffff !important;
|
caret-color: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
background-color: var(--ov-warn-color) !important;
|
background-color: var(--ov-warn-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.active-btn, ::ng-deep .active-btn {
|
.active-btn,
|
||||||
|
::ng-deep .active-btn {
|
||||||
background-color: var(--ov-tertiary-color) !important;
|
background-color: var(--ov-tertiary-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +42,8 @@
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#media-buttons-container button, #menu-buttons-container button {
|
#media-buttons-container button,
|
||||||
|
#menu-buttons-container button {
|
||||||
border-radius: var(--ov-buttons-radius);
|
border-radius: var(--ov-buttons-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +62,33 @@
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
padding: 0px 15px;
|
padding: 0px 15px;
|
||||||
}
|
}
|
||||||
|
#session-info-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colapsed {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#recording-tag {
|
||||||
|
padding: 0 15px;
|
||||||
|
background-color: var(--ov-warn-color);
|
||||||
|
border-radius: var(--ov-panel-radius);
|
||||||
|
width: fit-content;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
margin: auto;
|
||||||
|
animation: blinker 1.5s linear infinite;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#recording-tag mat-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
display: inline;
|
||||||
|
vertical-align: sub;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
#point {
|
#point {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
|
@ -79,12 +108,10 @@
|
||||||
width: 60px !important;
|
width: 60px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.tooltipList {
|
.tooltipList {
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#navChatButton .mat-badge-medium.mat-badge-overlap.mat-badge-before .mat-badge-content {
|
#navChatButton .mat-badge-medium.mat-badge-overlap.mat-badge-before .mat-badge-content {
|
||||||
left: -17px;
|
left: -17px;
|
||||||
}
|
}
|
||||||
|
@ -107,3 +134,11 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-menu-panel {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blinker {
|
||||||
|
50% { opacity: 0.2; }
|
||||||
|
}
|
|
@ -2,7 +2,13 @@
|
||||||
<div fxFlex="20%" fxLayoutAlign="start center" id="info-container">
|
<div fxFlex="20%" fxLayoutAlign="start center" id="info-container">
|
||||||
<div>
|
<div>
|
||||||
<img *ngIf="!isMinimal && showLogo" id="branding-logo" src="assets/images/logo.png" ovLogo />
|
<img *ngIf="!isMinimal && showLogo" id="branding-logo" src="assets/images/logo.png" ovLogo />
|
||||||
|
<div id="session-info-container" [class.colapsed]="isRecording">
|
||||||
<span id="session-name" *ngIf="!isMinimal && session && session.sessionId && showSessionName">{{ session.sessionId }}</span>
|
<span id="session-name" *ngIf="!isMinimal && session && session.sessionId && showSessionName">{{ session.sessionId }}</span>
|
||||||
|
<div id="recording-tag" *ngIf="isRecording">
|
||||||
|
<mat-icon>radio_button_checked</mat-icon>
|
||||||
|
<span>REC</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div fxFlex="60%" fxFlexOrder="2" fxLayoutAlign="center center" id="media-buttons-container">
|
<div fxFlex="60%" fxFlexOrder="2" fxLayoutAlign="center center" id="media-buttons-container">
|
||||||
|
@ -47,7 +53,7 @@
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
id="fullscreen-btn"
|
id="fullscreen-btn"
|
||||||
*ngIf="!isMinimal && showFullscreenButton"
|
*ngIf="!isMinimal && showFullscreenButton && !showBackgroundEffectsButton"
|
||||||
(click)="toggleFullscreen()"
|
(click)="toggleFullscreen()"
|
||||||
[disabled]="isConnectionLost"
|
[disabled]="isConnectionLost"
|
||||||
[class.active-btn]="isFullscreenActive"
|
[class.active-btn]="isFullscreenActive"
|
||||||
|
@ -56,6 +62,43 @@
|
||||||
<mat-icon *ngIf="!isFullscreenActive" matTooltip="Fullscreen">fullscreen</mat-icon>
|
<mat-icon *ngIf="!isFullscreenActive" matTooltip="Fullscreen">fullscreen</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
id="more-options-btn"
|
||||||
|
*ngIf="!isMinimal && !isOpenViduCE && showBackgroundEffectsButton"
|
||||||
|
[matMenuTriggerFor]="menu"
|
||||||
|
[disabled]="isConnectionLost"
|
||||||
|
>
|
||||||
|
<mat-icon matTooltip="More options">more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<!-- Fullscreen button -->
|
||||||
|
<button mat-menu-item id="fullscreen-btn" (click)="toggleFullscreen()">
|
||||||
|
<mat-icon *ngIf="!isFullscreenActive">fullscreen</mat-icon>
|
||||||
|
<span *ngIf="!isFullscreenActive">Fullscreen</span>
|
||||||
|
|
||||||
|
<mat-icon *ngIf="isFullscreenActive">fullscreen_exit</mat-icon>
|
||||||
|
<span *ngIf="isFullscreenActive">Exit fullscreen</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Recording button -->
|
||||||
|
<!-- <button
|
||||||
|
*ngIf="!isMinimal && showActivitiesPanelButton"
|
||||||
|
mat-menu-item
|
||||||
|
id="recording-btn"
|
||||||
|
(click)="toggleActivitiesPanel('recording')"
|
||||||
|
>
|
||||||
|
<mat-icon color="warn">radio_button_checked</mat-icon>
|
||||||
|
<span>Recording</span>
|
||||||
|
</button> -->
|
||||||
|
|
||||||
|
<!-- Virtual background button -->
|
||||||
|
<button *ngIf="!isMinimal && showBackgroundEffectsButton" mat-menu-item id="virtual-bg-btn" (click)="toggleBackgroundEffects()">
|
||||||
|
<mat-icon>auto_awesome</mat-icon>
|
||||||
|
<span>Background effects</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
|
||||||
<!-- External additional buttons -->
|
<!-- External additional buttons -->
|
||||||
<ng-container *ngIf="toolbarAdditionalButtonsTemplate">
|
<ng-container *ngIf="toolbarAdditionalButtonsTemplate">
|
||||||
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
||||||
|
@ -67,6 +110,19 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div fxFlex="20%" fxFlexOrder="3" fxLayoutAlign="end center" id="menu-buttons-container">
|
<div fxFlex="20%" fxFlexOrder="3" fxLayoutAlign="end center" id="menu-buttons-container">
|
||||||
|
<!-- Default activities button -->
|
||||||
|
<!-- <button
|
||||||
|
mat-icon-button
|
||||||
|
id="activities-panel-btn"
|
||||||
|
*ngIf="!isMinimal && showActivitiesPanelButton"
|
||||||
|
matTooltip="Activities"
|
||||||
|
(click)="toggleActivitiesPanel()"
|
||||||
|
[disabled]="isConnectionLost"
|
||||||
|
[class.active-btn]="isActivitiesOpened"
|
||||||
|
>
|
||||||
|
<mat-icon>category</mat-icon>
|
||||||
|
</button> -->
|
||||||
|
|
||||||
<!-- Default participants button -->
|
<!-- Default participants button -->
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
TemplateRef
|
TemplateRef,
|
||||||
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { skip, Subscription } from 'rxjs';
|
import { skip, Subscription } from 'rxjs';
|
||||||
import { TokenService } from '../../services/token/token.service';
|
import { TokenService } from '../../services/token/token.service';
|
||||||
|
@ -32,6 +33,9 @@ import {
|
||||||
} from '../../directives/template/openvidu-angular.directive';
|
} from '../../directives/template/openvidu-angular.directive';
|
||||||
import { ParticipantAbstractModel } from '../../models/participant.model';
|
import { ParticipantAbstractModel } from '../../models/participant.model';
|
||||||
import { PlatformService } from '../../services/platform/platform.service';
|
import { PlatformService } from '../../services/platform/platform.service';
|
||||||
|
import { MatMenuTrigger } from '@angular/material/menu';
|
||||||
|
import { RecordingInfo, RecordingService } from '../../services/recording/recording.service';
|
||||||
|
import { RecordingStatus } from '../../models/recording.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -49,6 +53,7 @@ import { PlatformService } from '../../services/platform/platform.service';
|
||||||
* | :----------------------------: | :-------: | :---------------------------------------------: |
|
* | :----------------------------: | :-------: | :---------------------------------------------: |
|
||||||
* | **screenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
|
* | **screenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
|
||||||
* | **fullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
* | **fullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
||||||
|
* | **backgroundEffectsButton** | `boolean` | {@link ToolbarBackgroundEffectsButtonDirective} |
|
||||||
* | **leaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
|
* | **leaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
|
||||||
* | **chatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
|
* | **chatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
|
||||||
* | **participantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
|
* | **participantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
|
||||||
|
@ -159,10 +164,21 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
@Output() onParticipantsPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
@Output() onParticipantsPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* TODO: WIP
|
||||||
|
* Provides event notifications that fire when background effects button has been clicked.
|
||||||
|
*/
|
||||||
|
// @Output() onBackgroundEffectsButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides event notifications that fire when chat panel button has been clicked.
|
* Provides event notifications that fire when chat panel button has been clicked.
|
||||||
*/
|
*/
|
||||||
@Output() onChatPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
@Output() onChatPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
|
@ -213,6 +229,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
isParticipantsOpened: boolean = false;
|
isParticipantsOpened: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
isActivitiesOpened: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -225,6 +246,12 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
showFullscreenButton: boolean = true;
|
showFullscreenButton: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
showBackgroundEffectsButton: boolean = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -233,6 +260,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
showParticipantsPanelButton: boolean = true;
|
showParticipantsPanelButton: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
showActivitiesPanelButton: boolean = true;
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -246,6 +278,16 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
showSessionName: boolean = true;
|
showSessionName: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
isRecording: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
isOpenViduCE: boolean;
|
||||||
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private minimalSub: Subscription;
|
private minimalSub: Subscription;
|
||||||
private panelTogglingSubscription: Subscription;
|
private panelTogglingSubscription: Subscription;
|
||||||
|
@ -253,7 +295,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
private localParticipantSubscription: Subscription;
|
private localParticipantSubscription: Subscription;
|
||||||
private screenshareButtonSub: Subscription;
|
private screenshareButtonSub: Subscription;
|
||||||
private fullscreenButtonSub: Subscription;
|
private fullscreenButtonSub: Subscription;
|
||||||
|
private backgroundEffectsButtonSub: Subscription;
|
||||||
private leaveButtonSub: Subscription;
|
private leaveButtonSub: Subscription;
|
||||||
|
private recordingSubscription: Subscription;
|
||||||
|
|
||||||
|
private activitiesPanelButtonSub: Subscription;
|
||||||
private participantsPanelButtonSub: Subscription;
|
private participantsPanelButtonSub: Subscription;
|
||||||
private chatPanelButtonSub: Subscription;
|
private chatPanelButtonSub: Subscription;
|
||||||
private displayLogoSub: Subscription;
|
private displayLogoSub: Subscription;
|
||||||
|
@ -275,7 +321,8 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
protected loggerSrv: LoggerService,
|
protected loggerSrv: LoggerService,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
private libService: OpenViduAngularConfigService,
|
private libService: OpenViduAngularConfigService,
|
||||||
private platformService: PlatformService
|
private platformService: PlatformService,
|
||||||
|
private recordingService: RecordingService
|
||||||
) {
|
) {
|
||||||
this.log = this.loggerSrv.get('ToolbarComponent');
|
this.log = this.loggerSrv.get('ToolbarComponent');
|
||||||
}
|
}
|
||||||
|
@ -310,12 +357,14 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
await this.oVDevicesService.initializeDevices();
|
await this.oVDevicesService.initializeDevices();
|
||||||
this.hasVideoDevices = this.oVDevicesService.hasVideoDeviceAvailable();
|
this.hasVideoDevices = this.oVDevicesService.hasVideoDeviceAvailable();
|
||||||
this.hasAudioDevices = this.oVDevicesService.hasAudioDeviceAvailable();
|
this.hasAudioDevices = this.oVDevicesService.hasAudioDeviceAvailable();
|
||||||
|
this.isOpenViduCE = this.openviduService.isOpenViduCE();
|
||||||
this.session = this.openviduService.getWebcamSession();
|
this.session = this.openviduService.getWebcamSession();
|
||||||
|
|
||||||
this.subscribeToUserMediaProperties();
|
this.subscribeToUserMediaProperties();
|
||||||
this.subscribeToReconnection();
|
this.subscribeToReconnection();
|
||||||
this.subscribeToMenuToggling();
|
this.subscribeToMenuToggling();
|
||||||
this.subscribeToChatMessages();
|
this.subscribeToChatMessages();
|
||||||
|
this.subscribeToRecordingStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
@ -324,12 +373,15 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
|
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
|
||||||
if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe();
|
if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe();
|
||||||
if (this.fullscreenButtonSub) this.fullscreenButtonSub.unsubscribe();
|
if (this.fullscreenButtonSub) this.fullscreenButtonSub.unsubscribe();
|
||||||
|
if (this.backgroundEffectsButtonSub) this.backgroundEffectsButtonSub.unsubscribe();
|
||||||
if (this.leaveButtonSub) this.leaveButtonSub.unsubscribe();
|
if (this.leaveButtonSub) this.leaveButtonSub.unsubscribe();
|
||||||
if (this.participantsPanelButtonSub) this.participantsPanelButtonSub.unsubscribe();
|
if (this.participantsPanelButtonSub) this.participantsPanelButtonSub.unsubscribe();
|
||||||
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
|
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
|
||||||
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
|
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
|
||||||
if (this.displaySessionNameSub) this.displaySessionNameSub.unsubscribe();
|
if (this.displaySessionNameSub) this.displaySessionNameSub.unsubscribe();
|
||||||
if (this.minimalSub) this.minimalSub.unsubscribe();
|
if (this.minimalSub) this.minimalSub.unsubscribe();
|
||||||
|
if (this.activitiesPanelButtonSub) this.activitiesPanelButtonSub.unsubscribe();
|
||||||
|
if (this.recordingSubscription) this.recordingSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -385,6 +437,23 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
this.onLeaveButtonClicked.emit();
|
this.onLeaveButtonClicked.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: WIP
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
toggleActivitiesPanel(expandPanel: string) {
|
||||||
|
// this.onActivitiesPanelButtonClicked.emit();
|
||||||
|
// this.panelService.togglePanel(PanelType.ACTIVITIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
toggleBackgroundEffects() {
|
||||||
|
// this.onBackgroundEffectsButtonClicked.emit();
|
||||||
|
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -425,6 +494,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: PanelType }) => {
|
this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: PanelType }) => {
|
||||||
this.isChatOpened = ev.opened && ev.type === PanelType.CHAT;
|
this.isChatOpened = ev.opened && ev.type === PanelType.CHAT;
|
||||||
this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
||||||
|
this.isActivitiesOpened = ev.opened && ev.type === PanelType.ACTIVITIES;
|
||||||
if (this.isChatOpened) {
|
if (this.isChatOpened) {
|
||||||
this.unreadMessages = 0;
|
this.unreadMessages = 0;
|
||||||
}
|
}
|
||||||
|
@ -451,6 +521,14 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscribeToRecordingStatus() {
|
||||||
|
//TODO: WIP
|
||||||
|
// this.recordingSubscription = this.recordingService.recordingStatusObs.pipe(skip(1)).subscribe((info: RecordingInfo) => {
|
||||||
|
// this.isRecording = info.status === RecordingStatus.STARTED;
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
private subscribeToToolbarDirectives() {
|
private subscribeToToolbarDirectives() {
|
||||||
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
|
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
|
||||||
this.isMinimal = value;
|
this.isMinimal = value;
|
||||||
|
@ -476,6 +554,14 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
||||||
this.showParticipantsPanelButton = value;
|
this.showParticipantsPanelButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
// this.activitiesPanelButtonSub = this.libService.activitiesPanelButtonObs.subscribe((value: boolean) => {
|
||||||
|
// this.showActivitiesPanelButton = value;
|
||||||
|
// this.cd.markForCheck();
|
||||||
|
// });
|
||||||
|
this.backgroundEffectsButtonSub = this.libService.backgroundEffectsButton.subscribe((value: boolean) => {
|
||||||
|
this.showBackgroundEffectsButton = value;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
this.displayLogoSub = this.libService.displayLogoObs.subscribe((value: boolean) => {
|
this.displayLogoSub = this.libService.displayLogoObs.subscribe((value: boolean) => {
|
||||||
this.showLogo = value;
|
this.showLogo = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div id="call-container">
|
<div id="call-container">
|
||||||
<div id="pre-join-container" *ngIf="showPrejoin && participantReady && !joinSessionClicked">
|
<div id="pre-join-container" *ngIf="showPrejoin && tokensReceived && participantReady && !joinSessionClicked">
|
||||||
<ov-pre-join (onJoinButtonClicked)="_onJoinButtonClicked()"></ov-pre-join>
|
<ov-pre-join (onJoinButtonClicked)="_onJoinButtonClicked()"></ov-pre-join>
|
||||||
<!-- <ov-user-settings (onJoinClicked)="_onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings> -->
|
<!-- <ov-user-settings (onJoinClicked)="_onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings> -->
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
<span>{{ errorMessage }}</span>
|
<span>{{ errorMessage }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="session-container" *ngIf="(joinSessionClicked || !showPrejoin) && participantReady && canPublish && !error">
|
<div id="session-container" *ngIf="(joinSessionClicked || !showPrejoin) && participantReady && tokensReceived && !error">
|
||||||
<ov-session (onSessionCreated)="_onSessionCreated($event)">
|
<ov-session (onSessionCreated)="_onSessionCreated($event)">
|
||||||
<ng-template #toolbar>
|
<ng-template #toolbar>
|
||||||
<ng-container *ngIf="openviduAngularToolbarTemplate">
|
<ng-container *ngIf="openviduAngularToolbarTemplate">
|
||||||
|
@ -68,6 +68,14 @@
|
||||||
<ng-container *ngTemplateOutlet="openviduAngularParticipantsPanelTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="openviduAngularParticipantsPanelTemplate"></ng-container>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #backgroundEffectsPanel>
|
||||||
|
<ov-background-effects-panel id="default-background-effects-panel"></ov-background-effects-panel>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #activitiesPanel>
|
||||||
|
<ng-container *ngTemplateOutlet="openviduAngularActivitiesPanelTemplate"></ng-container>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #additionalPanels>
|
<ng-template #additionalPanels>
|
||||||
<ng-container *ngTemplateOutlet="openviduAngularAdditionalPanelsTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="openviduAngularAdditionalPanelsTemplate"></ng-container>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -78,6 +86,14 @@
|
||||||
<ov-chat-panel id="default-chat-panel"></ov-chat-panel>
|
<ov-chat-panel id="default-chat-panel"></ov-chat-panel>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #defaultActivitiesPanel>
|
||||||
|
<!-- <ov-activities-panel
|
||||||
|
id="default-activities-panel"
|
||||||
|
(onStartRecordingClicked)="onStartRecordingClicked()"
|
||||||
|
(onStopRecordingClicked)="onStopRecordingClicked()"
|
||||||
|
></ov-activities-panel> -->
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #defaultParticipantsPanel>
|
<ng-template #defaultParticipantsPanel>
|
||||||
<ov-participants-panel id="default-participants-panel">
|
<ov-participants-panel id="default-participants-panel">
|
||||||
<ng-template #participantPanelItem let-participant>
|
<ng-template #participantPanelItem let-participant>
|
||||||
|
|
|
@ -23,7 +23,8 @@ import {
|
||||||
StreamDirective,
|
StreamDirective,
|
||||||
ToolbarAdditionalButtonsDirective,
|
ToolbarAdditionalButtonsDirective,
|
||||||
ToolbarAdditionalPanelButtonsDirective,
|
ToolbarAdditionalPanelButtonsDirective,
|
||||||
ToolbarDirective
|
ToolbarDirective,
|
||||||
|
ActivitiesPanelDirective
|
||||||
} from '../../directives/template/openvidu-angular.directive';
|
} from '../../directives/template/openvidu-angular.directive';
|
||||||
import { ILogger } from '../../models/logger.model';
|
import { ILogger } from '../../models/logger.model';
|
||||||
import { ParticipantAbstractModel, ParticipantProperties } from '../../models/participant.model';
|
import { ParticipantAbstractModel, ParticipantProperties } from '../../models/participant.model';
|
||||||
|
@ -32,7 +33,7 @@ import { ActionService } from '../../services/action/action.service';
|
||||||
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
||||||
import { DeviceService } from '../../services/device/device.service';
|
import { DeviceService } from '../../services/device/device.service';
|
||||||
import { LoggerService } from '../../services/logger/logger.service';
|
import { LoggerService } from '../../services/logger/logger.service';
|
||||||
import { OpenViduService } from '../../services/openvidu/openvidu.service';
|
import { OpenViduEdition, 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 { StorageService } from '../../services/storage/storage.service';
|
||||||
import { TokenService } from '../../services/token/token.service';
|
import { TokenService } from '../../services/token/token.service';
|
||||||
|
@ -57,6 +58,7 @@ import { TokenService } from '../../services/token/token.service';
|
||||||
* | **audioMuted** | `boolean` | {@link AudioMutedDirective} |
|
* | **audioMuted** | `boolean` | {@link AudioMutedDirective} |
|
||||||
* | **toolbarScreenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
|
* | **toolbarScreenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
|
||||||
* | **toolbarFullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
* | **toolbarFullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
||||||
|
* | **toolbarBackgroundEffectsButton** | `boolean` | {@link ToolbarBackgroundEffectsButtonDirective} |
|
||||||
* | **toolbarLeaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
|
* | **toolbarLeaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
|
||||||
* | **toolbarChatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
|
* | **toolbarChatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
|
||||||
* | **toolbarParticipantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
|
* | **toolbarParticipantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
|
||||||
|
@ -135,6 +137,11 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ContentChild(ChatPanelDirective) externalChatPanel: ChatPanelDirective;
|
@ContentChild(ChatPanelDirective) externalChatPanel: ChatPanelDirective;
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
@ContentChild(ActivitiesPanelDirective) externalActivitiesPanel: ActivitiesPanelDirective;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -174,6 +181,13 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ViewChild('defaultParticipantsPanel', { static: false, read: TemplateRef }) defaultParticipantsPanelTemplate: TemplateRef<any>;
|
@ViewChild('defaultParticipantsPanel', { static: false, read: TemplateRef }) defaultParticipantsPanelTemplate: TemplateRef<any>;
|
||||||
|
/**
|
||||||
|
* TODO: WIP
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
@ViewChild('defaultActivitiesPanel', { static: false, read: TemplateRef })
|
||||||
|
defaultActivitiesPanelTemplate: TemplateRef<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -195,6 +209,12 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>;
|
openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>;
|
||||||
|
/**
|
||||||
|
* TODO: WIP
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
openviduAngularActivitiesPanelTemplate: TemplateRef<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -244,6 +264,13 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
this.log.w('Tokens received');
|
this.log.w('Tokens received');
|
||||||
this.tokenService.setWebcamToken(tokens.webcam);
|
this.tokenService.setWebcamToken(tokens.webcam);
|
||||||
|
|
||||||
|
const openviduEdition = new URL(tokens.webcam).searchParams.get('edition');
|
||||||
|
if (!!openviduEdition) {
|
||||||
|
this.openviduService.setOpenViduEdition(OpenViduEdition.PRO);
|
||||||
|
} else {
|
||||||
|
this.openviduService.setOpenViduEdition(OpenViduEdition.CE);
|
||||||
|
}
|
||||||
|
|
||||||
if (tokens.screen) {
|
if (tokens.screen) {
|
||||||
this.tokenService.setScreenToken(tokens.screen);
|
this.tokenService.setScreenToken(tokens.screen);
|
||||||
} else {
|
} else {
|
||||||
|
@ -251,7 +278,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
this.libService.screenshareButton.next(false);
|
this.libService.screenshareButton.next(false);
|
||||||
this.log.w('No screen token found. Screenshare feature will be disabled');
|
this.log.w('No screen token found. Screenshare feature will be disabled');
|
||||||
}
|
}
|
||||||
this.canPublish = true;
|
this.tokensReceived = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +344,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
canPublish: boolean = false;
|
tokensReceived: boolean = false;
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -446,6 +473,15 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
||||||
this.openviduAngularChatPanelTemplate = this.defaultChatPanelTemplate;
|
this.openviduAngularChatPanelTemplate = this.defaultChatPanelTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: WIP
|
||||||
|
// if (this.externalActivitiesPanel) {
|
||||||
|
// this.log.d('Setting EXTERNAL ACTIVITIES PANEL');
|
||||||
|
// this.openviduAngularActivitiesPanelTemplate = this.externalActivitiesPanel.template;
|
||||||
|
// } else {
|
||||||
|
// this.log.d('Setting DEFAULT ACTIVITIES PANEL');
|
||||||
|
// this.openviduAngularActivitiesPanelTemplate = this.defaultActivitiesPanelTemplate;
|
||||||
|
// }
|
||||||
|
|
||||||
if (this.externalAdditionalPanels) {
|
if (this.externalAdditionalPanels) {
|
||||||
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
|
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
|
||||||
this.openviduAngularAdditionalPanelsTemplate = this.externalAdditionalPanels.template;
|
this.openviduAngularAdditionalPanelsTemplate = this.externalAdditionalPanels.template;
|
||||||
|
|
|
@ -13,7 +13,9 @@ import {
|
||||||
ToolbarChatPanelButtonDirective,
|
ToolbarChatPanelButtonDirective,
|
||||||
ToolbarDisplaySessionNameDirective,
|
ToolbarDisplaySessionNameDirective,
|
||||||
ToolbarDisplayLogoDirective,
|
ToolbarDisplayLogoDirective,
|
||||||
LogoDirective
|
LogoDirective,
|
||||||
|
ToolbarActivitiesPanelButtonDirective,
|
||||||
|
ToolbarBackgroundEffectsButtonDirective
|
||||||
} from './toolbar.directive';
|
} from './toolbar.directive';
|
||||||
import {
|
import {
|
||||||
AudioMutedDirective,
|
AudioMutedDirective,
|
||||||
|
@ -32,9 +34,11 @@ import {
|
||||||
AudioMutedDirective,
|
AudioMutedDirective,
|
||||||
ToolbarScreenshareButtonDirective,
|
ToolbarScreenshareButtonDirective,
|
||||||
ToolbarFullscreenButtonDirective,
|
ToolbarFullscreenButtonDirective,
|
||||||
|
ToolbarBackgroundEffectsButtonDirective,
|
||||||
ToolbarLeaveButtonDirective,
|
ToolbarLeaveButtonDirective,
|
||||||
ToolbarParticipantsPanelButtonDirective,
|
ToolbarParticipantsPanelButtonDirective,
|
||||||
ToolbarChatPanelButtonDirective,
|
ToolbarChatPanelButtonDirective,
|
||||||
|
ToolbarActivitiesPanelButtonDirective,
|
||||||
ToolbarDisplaySessionNameDirective,
|
ToolbarDisplaySessionNameDirective,
|
||||||
ToolbarDisplayLogoDirective,
|
ToolbarDisplayLogoDirective,
|
||||||
StreamDisplayParticipantNameDirective,
|
StreamDisplayParticipantNameDirective,
|
||||||
|
@ -51,9 +55,11 @@ import {
|
||||||
AudioMutedDirective,
|
AudioMutedDirective,
|
||||||
ToolbarScreenshareButtonDirective,
|
ToolbarScreenshareButtonDirective,
|
||||||
ToolbarFullscreenButtonDirective,
|
ToolbarFullscreenButtonDirective,
|
||||||
|
ToolbarBackgroundEffectsButtonDirective,
|
||||||
ToolbarLeaveButtonDirective,
|
ToolbarLeaveButtonDirective,
|
||||||
ToolbarParticipantsPanelButtonDirective,
|
ToolbarParticipantsPanelButtonDirective,
|
||||||
ToolbarChatPanelButtonDirective,
|
ToolbarChatPanelButtonDirective,
|
||||||
|
ToolbarActivitiesPanelButtonDirective,
|
||||||
ToolbarDisplaySessionNameDirective,
|
ToolbarDisplaySessionNameDirective,
|
||||||
ToolbarDisplayLogoDirective,
|
ToolbarDisplayLogoDirective,
|
||||||
StreamDisplayParticipantNameDirective,
|
StreamDisplayParticipantNameDirective,
|
||||||
|
|
|
@ -122,6 +122,65 @@ export class ToolbarFullscreenButtonDirective implements AfterViewInit, OnDestro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The **backgroundEffectsButton** directive allows show/hide the background effects toolbar button.
|
||||||
|
*
|
||||||
|
* Default: `true`
|
||||||
|
*
|
||||||
|
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* <ov-videoconference [toolbarBackgroundEffectsButton]="false"></ov-videoconference>
|
||||||
|
*
|
||||||
|
* \
|
||||||
|
* And it also can be used in the {@link ToolbarComponent}.
|
||||||
|
* @example
|
||||||
|
* <ov-toolbar [backgroundEffectsButton]="false"></ov-toolbar>
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'ov-videoconference[toolbarBackgroundEffectsButton], ov-toolbar[backgroundEffectsButton]'
|
||||||
|
})
|
||||||
|
export class ToolbarBackgroundEffectsButtonDirective implements AfterViewInit, OnDestroy {
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set toolbarBackgroundEffectsButton(value: boolean) {
|
||||||
|
this.backgroundEffectsValue = value;
|
||||||
|
this.update(this.backgroundEffectsValue);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set backgroundEffectsButton(value: boolean) {
|
||||||
|
this.backgroundEffectsValue = value;
|
||||||
|
this.update(this.backgroundEffectsValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private backgroundEffectsValue: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.update(this.backgroundEffectsValue);
|
||||||
|
}
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
private clear() {
|
||||||
|
this.backgroundEffectsValue = true;
|
||||||
|
this.update(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(value: boolean) {
|
||||||
|
if (this.libService.backgroundEffectsButton.getValue() !== value) {
|
||||||
|
this.libService.backgroundEffectsButton.next(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The **leaveButton** directive allows show/hide the leave toolbar button.
|
* The **leaveButton** directive allows show/hide the leave toolbar button.
|
||||||
*
|
*
|
||||||
|
@ -302,6 +361,68 @@ export class ToolbarChatPanelButtonDirective implements AfterViewInit, OnDestroy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The **activitiesPanelButton** directive allows show/hide the activities panel toolbar button.
|
||||||
|
*
|
||||||
|
* Default: `true`
|
||||||
|
*
|
||||||
|
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* <ov-videoconference [toolbarActivitiesPanelButton]="false"></ov-videoconference>
|
||||||
|
*
|
||||||
|
* \
|
||||||
|
* And it also can be used in the {@link ToolbarComponent}.
|
||||||
|
* @example
|
||||||
|
* <ov-toolbar [activitiesPanelButton]="false"></ov-toolbar>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'ov-videoconference[toolbarActivitiesPanelButton], ov-toolbar[activitiesPanelButton]'
|
||||||
|
})
|
||||||
|
export class ToolbarActivitiesPanelButtonDirective implements AfterViewInit, OnDestroy {
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set toolbarActivitiesPanelButton(value: boolean) {
|
||||||
|
this.toolbarActivitiesPanelValue = value;
|
||||||
|
this.update(this.toolbarActivitiesPanelValue);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set chatPanelButton(value: boolean) {
|
||||||
|
this.toolbarActivitiesPanelValue = value;
|
||||||
|
this.update(this.toolbarActivitiesPanelValue);
|
||||||
|
}
|
||||||
|
private toolbarActivitiesPanelValue: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.update(this.toolbarActivitiesPanelValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
private clear() {
|
||||||
|
this.toolbarActivitiesPanelValue = true;
|
||||||
|
this.update(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(value: boolean) {
|
||||||
|
if (this.libService.activitiesPanelButton.getValue() !== value) {
|
||||||
|
this.libService.activitiesPanelButton.next(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The **displaySessionName** directive allows show/hide the session name.
|
* The **displaySessionName** directive allows show/hide the session name.
|
||||||
*
|
*
|
||||||
|
|
|
@ -10,7 +10,9 @@ import {
|
||||||
ToolbarAdditionalButtonsDirective,
|
ToolbarAdditionalButtonsDirective,
|
||||||
ToolbarDirective,
|
ToolbarDirective,
|
||||||
ToolbarAdditionalPanelButtonsDirective,
|
ToolbarAdditionalPanelButtonsDirective,
|
||||||
AdditionalPanelsDirective
|
AdditionalPanelsDirective,
|
||||||
|
ActivitiesPanelDirective,
|
||||||
|
BackgroundEffectsPanelDirective
|
||||||
} from './openvidu-angular.directive';
|
} from './openvidu-angular.directive';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -25,7 +27,9 @@ import {
|
||||||
ToolbarDirective,
|
ToolbarDirective,
|
||||||
ToolbarAdditionalButtonsDirective,
|
ToolbarAdditionalButtonsDirective,
|
||||||
ToolbarAdditionalPanelButtonsDirective,
|
ToolbarAdditionalPanelButtonsDirective,
|
||||||
ParticipantPanelItemElementsDirective
|
ParticipantPanelItemElementsDirective,
|
||||||
|
ActivitiesPanelDirective,
|
||||||
|
BackgroundEffectsPanelDirective
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ChatPanelDirective,
|
ChatPanelDirective,
|
||||||
|
@ -38,7 +42,9 @@ import {
|
||||||
ToolbarDirective,
|
ToolbarDirective,
|
||||||
ToolbarAdditionalButtonsDirective,
|
ToolbarAdditionalButtonsDirective,
|
||||||
ToolbarAdditionalPanelButtonsDirective,
|
ToolbarAdditionalPanelButtonsDirective,
|
||||||
ParticipantPanelItemElementsDirective
|
ParticipantPanelItemElementsDirective,
|
||||||
|
ActivitiesPanelDirective,
|
||||||
|
BackgroundEffectsPanelDirective
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class OpenViduAngularDirectiveModule {}
|
export class OpenViduAngularDirectiveModule {}
|
||||||
|
|
|
@ -364,6 +364,29 @@ export class ChatPanelDirective {
|
||||||
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
|
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: WIP. backgroundEffectsPanel does not provides customization
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[ovBackgroundEffectsPanel]'
|
||||||
|
})
|
||||||
|
export class BackgroundEffectsPanelDirective {
|
||||||
|
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: WIP
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[ovActivitiesPanel]'
|
||||||
|
})
|
||||||
|
export class ActivitiesPanelDirective {
|
||||||
|
constructor(public template: TemplateRef<any>, public viewContainer: ViewContainerRef) {}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ***ovParticipantsPanel** directive allows to replace the default participants panel template injecting your own component.
|
* The ***ovParticipantsPanel** directive allows to replace the default participants panel template injecting your own component.
|
||||||
* Here we're going to redefine the participants template in a few code lines.
|
* Here we're going to redefine the participants template in a few code lines.
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
export enum PanelType {
|
export enum PanelType {
|
||||||
CHAT = 'chat',
|
CHAT = 'chat',
|
||||||
PARTICIPANTS = 'participants'
|
PARTICIPANTS = 'participants',
|
||||||
|
BACKGROUND_EFFECTS = 'background-effects',
|
||||||
|
ACTIVITIES = 'activities'
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum RecordingStatus {
|
||||||
|
STARTED = 'STARTED',
|
||||||
|
STOPPED = 'STOPPED'
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ import { OverlayContainer } from '@angular/cdk/overlay';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatListModule } from '@angular/material/list';
|
import { MatListModule } from '@angular/material/list';
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
|
import {MatExpansionModule} from '@angular/material/expansion';
|
||||||
|
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
@ -63,6 +64,9 @@ import { PreJoinComponent } from './components/pre-join/pre-join.component';
|
||||||
import { AvatarProfileComponent } from './components/avatar-profile/avatar-profile.component';
|
import { AvatarProfileComponent } from './components/avatar-profile/avatar-profile.component';
|
||||||
import { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.directive.module';
|
import { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.directive.module';
|
||||||
import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
||||||
|
import { BackgroundEffectsPanelComponent } from './components/panel/background-effects-panel/background-effects-panel.component';
|
||||||
|
import { ActivitiesPanelComponent } from './components/panel/activities-panel/activities-panel.component';
|
||||||
|
import { RecordingActivityComponent } from './components/panel/activities-panel/recording-activity-panel/recording-activity.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -84,6 +88,9 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
||||||
PanelComponent,
|
PanelComponent,
|
||||||
AvatarProfileComponent,
|
AvatarProfileComponent,
|
||||||
PreJoinComponent,
|
PreJoinComponent,
|
||||||
|
BackgroundEffectsPanelComponent,
|
||||||
|
ActivitiesPanelComponent,
|
||||||
|
RecordingActivityComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
@ -111,6 +118,7 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
MatDividerModule,
|
MatDividerModule,
|
||||||
MatListModule,
|
MatListModule,
|
||||||
|
MatExpansionModule,
|
||||||
OpenViduAngularDirectiveModule,
|
OpenViduAngularDirectiveModule,
|
||||||
ApiDirectiveModule
|
ApiDirectiveModule
|
||||||
],
|
],
|
||||||
|
@ -137,6 +145,8 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
||||||
PanelComponent,
|
PanelComponent,
|
||||||
ParticipantsPanelComponent,
|
ParticipantsPanelComponent,
|
||||||
ParticipantPanelItemComponent,
|
ParticipantPanelItemComponent,
|
||||||
|
BackgroundEffectsPanelComponent,
|
||||||
|
ActivitiesPanelComponent,
|
||||||
ChatPanelComponent,
|
ChatPanelComponent,
|
||||||
SessionComponent,
|
SessionComponent,
|
||||||
LayoutComponent,
|
LayoutComponent,
|
||||||
|
|
|
@ -36,6 +36,9 @@ export class OpenViduAngularConfigService {
|
||||||
chatPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
chatPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
chatPanelButtonObs: Observable<boolean>;
|
chatPanelButtonObs: Observable<boolean>;
|
||||||
|
|
||||||
|
activitiesPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
|
activitiesPanelButtonObs: Observable<boolean>;
|
||||||
|
|
||||||
displaySessionName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
displaySessionName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
displaySessionNameObs: Observable<boolean>;
|
displaySessionNameObs: Observable<boolean>;
|
||||||
|
|
||||||
|
@ -49,6 +52,8 @@ export class OpenViduAngularConfigService {
|
||||||
settingsButtonObs: Observable<boolean>;
|
settingsButtonObs: Observable<boolean>;
|
||||||
participantItemMuteButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
participantItemMuteButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
participantItemMuteButtonObs: Observable<boolean>;
|
participantItemMuteButtonObs: Observable<boolean>;
|
||||||
|
backgroundEffectsButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
|
backgroundEffectsButtonObs: Observable<boolean>;
|
||||||
|
|
||||||
constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) {
|
constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) {
|
||||||
this.configuration = config;
|
this.configuration = config;
|
||||||
|
@ -62,9 +67,11 @@ export class OpenViduAngularConfigService {
|
||||||
//Toolbar observables
|
//Toolbar observables
|
||||||
this.screenshareButtonObs = this.screenshareButton.asObservable();
|
this.screenshareButtonObs = this.screenshareButton.asObservable();
|
||||||
this.fullscreenButtonObs = this.fullscreenButton.asObservable();
|
this.fullscreenButtonObs = this.fullscreenButton.asObservable();
|
||||||
|
this.backgroundEffectsButtonObs = this.backgroundEffectsButton.asObservable();
|
||||||
this.leaveButtonObs = this.leaveButton.asObservable();
|
this.leaveButtonObs = this.leaveButton.asObservable();
|
||||||
this.participantsPanelButtonObs = this.participantsPanelButton.asObservable();
|
this.participantsPanelButtonObs = this.participantsPanelButton.asObservable();
|
||||||
this.chatPanelButtonObs = this.chatPanelButton.asObservable();
|
this.chatPanelButtonObs = this.chatPanelButton.asObservable();
|
||||||
|
this.activitiesPanelButtonObs = this.activitiesPanelButton.asObservable();
|
||||||
this.displaySessionNameObs = this.displaySessionName.asObservable();
|
this.displaySessionNameObs = this.displaySessionName.asObservable();
|
||||||
this.displayLogoObs = this.displayLogo.asObservable();
|
this.displayLogoObs = this.displayLogo.asObservable();
|
||||||
//Stream observables
|
//Stream observables
|
||||||
|
@ -82,10 +89,6 @@ export class OpenViduAngularConfigService {
|
||||||
return this.configuration?.production;
|
return this.configuration?.production;
|
||||||
}
|
}
|
||||||
|
|
||||||
// isWebcomponent(): boolean {
|
|
||||||
// return this.configuration?.webcomponent;
|
|
||||||
// }
|
|
||||||
|
|
||||||
hasParticipantFactory(): boolean {
|
hasParticipantFactory(): boolean {
|
||||||
return typeof this.getConfig().participantFactory === 'function';
|
return typeof this.getConfig().participantFactory === 'function';
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,17 @@ import { ScreenType, VideoType } from '../../models/video-type.model';
|
||||||
import { ParticipantService } from '../participant/participant.service';
|
import { ParticipantService } from '../participant/participant.service';
|
||||||
import { TokenService } from '../token/token.service';
|
import { TokenService } from '../token/token.service';
|
||||||
|
|
||||||
|
export enum OpenViduEdition {
|
||||||
|
CE = 'CE',
|
||||||
|
PRO = 'PRO',
|
||||||
|
ENTERPRISE = 'ENTERPRISE'
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class OpenViduService {
|
export class OpenViduService {
|
||||||
|
private ovEdition: OpenViduEdition;
|
||||||
protected OV: OpenVidu = null;
|
protected OV: OpenVidu = null;
|
||||||
protected OVScreen: OpenVidu = null;
|
protected OVScreen: OpenVidu = null;
|
||||||
protected webcamSession: Session = null;
|
protected webcamSession: Session = null;
|
||||||
|
@ -60,6 +67,20 @@ export class OpenViduService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
isOpenViduCE(): boolean {
|
||||||
|
return this.ovEdition === OpenViduEdition.CE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
setOpenViduEdition(edition: OpenViduEdition) {
|
||||||
|
this.ovEdition = edition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RecordingService } from './recording.service';
|
||||||
|
|
||||||
|
describe('RecordingService', () => {
|
||||||
|
let service: RecordingService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(RecordingService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { RecordingEvent } from 'openvidu-browser';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { RecordingStatus } from '../../models/recording.model';
|
||||||
|
|
||||||
|
export interface RecordingInfo {
|
||||||
|
status: RecordingStatus;
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
reason?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class RecordingService {
|
||||||
|
/**
|
||||||
|
* Recording status Observable which pushes the recording state in every update.
|
||||||
|
*/
|
||||||
|
recordingStatusObs: Observable<RecordingInfo>;
|
||||||
|
private recordingStatus = <BehaviorSubject<RecordingInfo>>new BehaviorSubject(null);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.recordingStatusObs = this.recordingStatus.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
startRecording(event: RecordingEvent) {
|
||||||
|
const info: RecordingInfo = {
|
||||||
|
status: RecordingStatus.STARTED,
|
||||||
|
id: event.id,
|
||||||
|
name: event.name,
|
||||||
|
reason: event.reason
|
||||||
|
};
|
||||||
|
this.recordingStatus.next(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopRecording(event: RecordingEvent) {
|
||||||
|
const info: RecordingInfo = {
|
||||||
|
status: RecordingStatus.STOPPED,
|
||||||
|
id: event.id,
|
||||||
|
name: event.name,
|
||||||
|
reason: event.reason
|
||||||
|
};
|
||||||
|
this.recordingStatus.next(info);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,8 @@ export * from './lib/components/videoconference/videoconference.component';
|
||||||
export * from './lib/components/toolbar/toolbar.component';
|
export * from './lib/components/toolbar/toolbar.component';
|
||||||
export * from './lib/components/panel/panel.component';
|
export * from './lib/components/panel/panel.component';
|
||||||
export * from './lib/components/panel/chat-panel/chat-panel.component';
|
export * from './lib/components/panel/chat-panel/chat-panel.component';
|
||||||
|
export * from './lib/components/panel/background-effects-panel/background-effects-panel.component';
|
||||||
|
export * from './lib/components/panel/activities-panel/activities-panel.component';
|
||||||
export * from './lib/components/panel/participants-panel/participants-panel/participants-panel.component';
|
export * from './lib/components/panel/participants-panel/participants-panel/participants-panel.component';
|
||||||
export * from './lib/components/panel/participants-panel/participant-panel-item/participant-panel-item.component';
|
export * from './lib/components/panel/participants-panel/participant-panel-item/participant-panel-item.component';
|
||||||
export * from './lib/components/session/session.component';
|
export * from './lib/components/session/session.component';
|
||||||
|
|
Loading…
Reference in New Issue