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>
|
||||
|
||||
<!-- 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 -->
|
||||
<ng-container *ngIf="additionalPanelsTemplate && isExternalPanelOpened">
|
||||
<ng-container *ngTemplateOutlet="additionalPanelsTemplate"></ng-container>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core';
|
||||
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 { PanelService } from '../../services/panel/panel.service';
|
||||
|
||||
|
@ -53,6 +59,15 @@ export class PanelComponent implements OnInit {
|
|||
*/
|
||||
@ContentChild('participantsPanel', { read: TemplateRef }) participantsPanelTemplate: TemplateRef<any>;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@ContentChild('backgroundEffectsPanel', { read: TemplateRef }) backgroundEffectsPanelTemplate: TemplateRef<any>;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@ContentChild('activitiesPanel', { read: TemplateRef }) activitiesPanelTemplate: TemplateRef<any>;
|
||||
/**
|
||||
* @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)
|
||||
set externalChatPanel(externalChatPanel: ChatPanelDirective) {
|
||||
// This directive will has value only when CHAT PANEL component tagged with '*ovChatPanel'
|
||||
|
@ -92,6 +125,8 @@ export class PanelComponent implements OnInit {
|
|||
|
||||
isParticipantsPanelOpened: boolean;
|
||||
isChatPanelOpened: boolean;
|
||||
isBackgroundEffectsPanelOpened: boolean;
|
||||
isActivitiesPanelOpened: boolean;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -115,9 +150,13 @@ export class PanelComponent implements OnInit {
|
|||
}
|
||||
|
||||
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.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.cd.markForCheck();
|
||||
});
|
||||
|
|
|
@ -16,11 +16,28 @@ hr {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
ov-layout {
|
||||
height: -webkit-fill-available;
|
||||
height: -moz-available;
|
||||
width: -webkit-fill-available;
|
||||
width: -moz-available;
|
||||
#prejoin-container ::ng-deep .sidenav-container {
|
||||
padding-top: 0px !important;
|
||||
}
|
||||
#prejoin-container ::ng-deep #background-effects-container {
|
||||
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 {
|
||||
|
|
|
@ -1,24 +1,51 @@
|
|||
<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">
|
||||
<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>
|
||||
<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>
|
||||
</ng-template>
|
||||
</ov-layout>
|
||||
</ng-template>
|
||||
</ov-session>
|
||||
</div>
|
||||
<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.gt-sm="column" fxLayout.lt-md="column" fxLayoutGap="10px" fxFlex="33%">
|
||||
<div fxFlex.gt-sm="100%" fxFlex.lt-md="33%" fxLayoutAlign="center center" fxFlexFill class="nickname-container">
|
||||
<h4 *ngIf="windowSize >= 960">Set your name</h4>
|
||||
<hr *ngIf="windowSize >= 960"/>
|
||||
<hr *ngIf="windowSize >= 960" />
|
||||
<div id="nickname-input-container">
|
||||
<button mat-icon-button disabled>
|
||||
<mat-icon>person</mat-icon>
|
||||
</button>
|
||||
<mat-form-field appearance="standard">
|
||||
<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>
|
||||
</div>
|
||||
<!-- <mat-button-toggle-group style="border-radius: 20px">
|
||||
|
@ -39,7 +66,7 @@
|
|||
|
||||
<div fxFlex.gt-sm="100%" fxFlex.lt-md="33%" fxLayoutAlign="center center" fxFlexFill class="buttons-container">
|
||||
<h4 *ngIf="windowSize >= 960">Choose your devices</h4>
|
||||
<hr *ngIf="windowSize >= 960"/>
|
||||
<hr *ngIf="windowSize >= 960" />
|
||||
<!-- Camera -->
|
||||
<div class="device-container-element">
|
||||
<button
|
||||
|
@ -54,7 +81,11 @@
|
|||
</button>
|
||||
<mat-form-field>
|
||||
<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">
|
||||
{{ camera.label }}
|
||||
</mat-option>
|
||||
|
@ -76,7 +107,11 @@
|
|||
</button>
|
||||
<mat-form-field>
|
||||
<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">
|
||||
{{ microphone.label }}
|
||||
</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 { Subscription } from 'rxjs';
|
||||
import { CustomDevice } from '../../models/device.model';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { PanelType } from '../../models/panel.model';
|
||||
import { ParticipantAbstractModel } from '../../models/participant.model';
|
||||
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
||||
import { DeviceService } from '../../services/device/device.service';
|
||||
import { LayoutService } from '../../services/layout/layout.service';
|
||||
import { LoggerService } from '../../services/logger/logger.service';
|
||||
import { OpenViduService } from '../../services/openvidu/openvidu.service';
|
||||
import { PanelService } from '../../services/panel/panel.service';
|
||||
import { ParticipantService } from '../../services/participant/participant.service';
|
||||
import { StorageService } from '../../services/storage/storage.service';
|
||||
|
||||
|
@ -33,9 +43,21 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
|||
hasAudioDevices: boolean;
|
||||
isLoading = true;
|
||||
nickname: string;
|
||||
isOpenViduCE: boolean;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
showBackgroundEffectsButton: boolean = true;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
isMinimal: boolean = false;
|
||||
|
||||
private log: ILogger;
|
||||
private localParticipantSubscription: Subscription;
|
||||
private screenShareStateSubscription: Subscription;
|
||||
private minimalSub: Subscription;
|
||||
private backgroundEffectsButtonSub: Subscription;
|
||||
|
||||
@HostListener('window:resize')
|
||||
sizeChange() {
|
||||
|
@ -49,13 +71,17 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
|||
private loggerSrv: LoggerService,
|
||||
private openviduService: OpenViduService,
|
||||
private participantService: ParticipantService,
|
||||
protected panelService: PanelService,
|
||||
private libService: OpenViduAngularConfigService,
|
||||
private storageSrv: StorageService
|
||||
) {
|
||||
this.log = this.loggerSrv.get('PreJoinComponent');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.subscribeToPrejoinDirectives();
|
||||
this.subscribeToLocalParticipantEvents();
|
||||
this.isOpenViduCE = this.openviduService.isOpenViduCE();
|
||||
|
||||
this.windowSize = window.innerWidth;
|
||||
this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable();
|
||||
|
@ -79,6 +105,9 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
|||
if (this.screenShareStateSubscription) {
|
||||
this.screenShareStateSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
if (this.backgroundEffectsButtonSub) this.backgroundEffectsButtonSub.unsubscribe();
|
||||
if (this.minimalSub) this.minimalSub.unsubscribe();
|
||||
}
|
||||
|
||||
async onCameraSelected(event: any) {
|
||||
|
@ -138,6 +167,10 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
|||
this.onJoinButtonClicked.emit();
|
||||
}
|
||||
|
||||
toggleBackgroundEffects() {
|
||||
this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS);
|
||||
}
|
||||
|
||||
private subscribeToLocalParticipantEvents() {
|
||||
this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((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.
|
||||
//? It's not longer needed
|
||||
// private handlePublisherSuccess(publisher: Publisher) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div id="session-container">
|
||||
<mat-sidenav-container class="sidenav-container">
|
||||
<mat-sidenav-container #videoContainer class="sidenav-container">
|
||||
<mat-sidenav
|
||||
#sidenav
|
||||
mode="{{ sidenavMode }}"
|
||||
|
@ -19,7 +19,7 @@
|
|||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
|
||||
<div id="footer-container">
|
||||
<div id="footer-container" *ngIf="toolbarTemplate">
|
||||
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,14 +2,16 @@ import {
|
|||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ContentChild,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
TemplateRef,
|
||||
ViewChild
|
||||
} 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 { ILogger } from '../../models/logger.model';
|
||||
|
@ -27,7 +29,7 @@ import { LayoutService } from '../../services/layout/layout.service';
|
|||
import { Subscription, skip } from 'rxjs';
|
||||
import { PanelType } from '../../models/panel.model';
|
||||
import { PanelService } from '../../services/panel/panel.service';
|
||||
import { PlatformService } from '../../services/platform/platform.service';
|
||||
import { RecordingService } from '../../services/recording/recording.service';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -44,6 +46,7 @@ export class SessionComponent implements OnInit {
|
|||
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>;
|
||||
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>;
|
||||
|
||||
@Input() usedInPrejoinPage = false;
|
||||
@Output() onSessionCreated = new EventEmitter<any>();
|
||||
|
||||
session: Session;
|
||||
|
@ -69,7 +72,8 @@ export class SessionComponent implements OnInit {
|
|||
protected chatService: ChatService,
|
||||
protected tokenService: TokenService,
|
||||
protected layoutService: LayoutService,
|
||||
protected panelService: PanelService
|
||||
protected panelService: PanelService,
|
||||
private recordingService: RecordingService
|
||||
) {
|
||||
this.log = this.loggerSrv.get('SessionComponent');
|
||||
}
|
||||
|
@ -94,7 +98,19 @@ export class SessionComponent implements OnInit {
|
|||
}, 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() {
|
||||
if(!this.usedInPrejoinPage){
|
||||
this.session = this.openviduService.getWebcamSession();
|
||||
this.sessionScreen = this.openviduService.getScreenSession();
|
||||
this.subscribeToConnectionCreatedAndDestroyed();
|
||||
|
@ -104,6 +120,9 @@ export class SessionComponent implements OnInit {
|
|||
this.subscribeToNicknameChanged();
|
||||
this.chatService.subscribeToChat();
|
||||
this.subscribeToReconnection();
|
||||
// if(RecordingEnabled){
|
||||
this.subscribeToRecordingEvents();
|
||||
// }
|
||||
this.onSessionCreated.emit(this.session);
|
||||
|
||||
await this.connectToSession();
|
||||
|
@ -113,6 +132,7 @@ export class SessionComponent implements OnInit {
|
|||
// this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), false);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// 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;
|
||||
}
|
||||
|
||||
mat-error {
|
||||
text-align: center;
|
||||
color: #353535;
|
||||
}
|
||||
|
||||
video {
|
||||
-o-object-fit: cover;
|
||||
|
@ -115,17 +111,6 @@
|
|||
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 {
|
||||
caret-color: #ffffff !important;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
right: 0;
|
||||
}
|
||||
|
||||
#info-container>div {
|
||||
#info-container > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -33,7 +33,8 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -41,7 +42,8 @@
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -53,15 +55,42 @@
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
#session-name {
|
||||
#session-name {
|
||||
font-family: 'Ubuntu', sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
height: fit-content;
|
||||
padding: 0px 15px;
|
||||
}
|
||||
}
|
||||
#session-info-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#point {
|
||||
.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 {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
|
@ -71,39 +100,45 @@
|
|||
background-color: #ffa600;
|
||||
border: 1px solid #000;
|
||||
z-index: 99999;
|
||||
}
|
||||
}
|
||||
|
||||
#leave-btn {
|
||||
#leave-btn {
|
||||
background-color: var(--ov-warn-color) !important;
|
||||
border-radius: var(--ov-leave-button-radius) !important;
|
||||
width: 60px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tooltipList {
|
||||
.tooltipList {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#navChatButton .mat-badge-medium.mat-badge-above .mat-badge-content {
|
||||
#navChatButton .mat-badge-medium.mat-badge-above .mat-badge-content {
|
||||
top: -6px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-icon-button[disabled] {
|
||||
.mat-icon-button[disabled] {
|
||||
color: #fff;
|
||||
}
|
||||
@media (max-width: 750px) {
|
||||
}
|
||||
@media (max-width: 750px) {
|
||||
#session-name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 850px) {
|
||||
@media (max-width: 850px) {
|
||||
#branding-logo {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .mat-menu-panel {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% { opacity: 0.2; }
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
<mat-toolbar id="toolbar" role="heading" fxLayout fxLayoutAlign="center" fxLayoutGap="10px">
|
||||
<div fxFlex="20%" fxLayoutAlign="start center" id="info-container">
|
||||
<div >
|
||||
<div>
|
||||
<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>
|
||||
<div id="recording-tag" *ngIf="isRecording">
|
||||
<mat-icon>radio_button_checked</mat-icon>
|
||||
<span>REC</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div fxFlex="60%" fxFlexOrder="2" fxLayoutAlign="center center" id="media-buttons-container">
|
||||
|
@ -47,7 +53,7 @@
|
|||
<button
|
||||
mat-icon-button
|
||||
id="fullscreen-btn"
|
||||
*ngIf="!isMinimal && showFullscreenButton"
|
||||
*ngIf="!isMinimal && showFullscreenButton && !showBackgroundEffectsButton"
|
||||
(click)="toggleFullscreen()"
|
||||
[disabled]="isConnectionLost"
|
||||
[class.active-btn]="isFullscreenActive"
|
||||
|
@ -56,6 +62,43 @@
|
|||
<mat-icon *ngIf="!isFullscreenActive" matTooltip="Fullscreen">fullscreen</mat-icon>
|
||||
</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 -->
|
||||
<ng-container *ngIf="toolbarAdditionalButtonsTemplate">
|
||||
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
||||
|
@ -67,6 +110,19 @@
|
|||
</button>
|
||||
</div>
|
||||
<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 -->
|
||||
<button
|
||||
mat-icon-button
|
||||
|
|
|
@ -8,7 +8,8 @@ import {
|
|||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
TemplateRef
|
||||
TemplateRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { skip, Subscription } from 'rxjs';
|
||||
import { TokenService } from '../../services/token/token.service';
|
||||
|
@ -32,6 +33,9 @@ import {
|
|||
} from '../../directives/template/openvidu-angular.directive';
|
||||
import { ParticipantAbstractModel } from '../../models/participant.model';
|
||||
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} |
|
||||
* | **fullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
||||
* | **backgroundEffectsButton** | `boolean` | {@link ToolbarBackgroundEffectsButtonDirective} |
|
||||
* | **leaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
|
||||
* | **chatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
|
||||
* | **participantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
|
||||
|
@ -159,10 +164,21 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
*/
|
||||
@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.
|
||||
*/
|
||||
@Output() onChatPanelButtonClicked: EventEmitter<void> = new EventEmitter<any>();
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
|
@ -213,6 +229,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
*/
|
||||
isParticipantsOpened: boolean = false;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
isActivitiesOpened: boolean = false;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -225,6 +246,12 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
* @ignore
|
||||
*/
|
||||
showFullscreenButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
showBackgroundEffectsButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -233,6 +260,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
* @ignore
|
||||
*/
|
||||
showParticipantsPanelButton: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
showActivitiesPanelButton: boolean = true;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -246,6 +278,16 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
*/
|
||||
showSessionName: boolean = true;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
isRecording: boolean = false;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
isOpenViduCE: boolean;
|
||||
|
||||
private log: ILogger;
|
||||
private minimalSub: Subscription;
|
||||
private panelTogglingSubscription: Subscription;
|
||||
|
@ -253,7 +295,11 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
private localParticipantSubscription: Subscription;
|
||||
private screenshareButtonSub: Subscription;
|
||||
private fullscreenButtonSub: Subscription;
|
||||
private backgroundEffectsButtonSub: Subscription;
|
||||
private leaveButtonSub: Subscription;
|
||||
private recordingSubscription: Subscription;
|
||||
|
||||
private activitiesPanelButtonSub: Subscription;
|
||||
private participantsPanelButtonSub: Subscription;
|
||||
private chatPanelButtonSub: Subscription;
|
||||
private displayLogoSub: Subscription;
|
||||
|
@ -275,7 +321,8 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
protected loggerSrv: LoggerService,
|
||||
private cd: ChangeDetectorRef,
|
||||
private libService: OpenViduAngularConfigService,
|
||||
private platformService: PlatformService
|
||||
private platformService: PlatformService,
|
||||
private recordingService: RecordingService
|
||||
) {
|
||||
this.log = this.loggerSrv.get('ToolbarComponent');
|
||||
}
|
||||
|
@ -310,12 +357,14 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
await this.oVDevicesService.initializeDevices();
|
||||
this.hasVideoDevices = this.oVDevicesService.hasVideoDeviceAvailable();
|
||||
this.hasAudioDevices = this.oVDevicesService.hasAudioDeviceAvailable();
|
||||
this.isOpenViduCE = this.openviduService.isOpenViduCE();
|
||||
this.session = this.openviduService.getWebcamSession();
|
||||
|
||||
this.subscribeToUserMediaProperties();
|
||||
this.subscribeToReconnection();
|
||||
this.subscribeToMenuToggling();
|
||||
this.subscribeToChatMessages();
|
||||
this.subscribeToRecordingStatus();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -324,12 +373,15 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe();
|
||||
if (this.screenshareButtonSub) this.screenshareButtonSub.unsubscribe();
|
||||
if (this.fullscreenButtonSub) this.fullscreenButtonSub.unsubscribe();
|
||||
if (this.backgroundEffectsButtonSub) this.backgroundEffectsButtonSub.unsubscribe();
|
||||
if (this.leaveButtonSub) this.leaveButtonSub.unsubscribe();
|
||||
if (this.participantsPanelButtonSub) this.participantsPanelButtonSub.unsubscribe();
|
||||
if (this.chatPanelButtonSub) this.chatPanelButtonSub.unsubscribe();
|
||||
if (this.displayLogoSub) this.displayLogoSub.unsubscribe();
|
||||
if (this.displaySessionNameSub) this.displaySessionNameSub.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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -425,6 +494,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: PanelType }) => {
|
||||
this.isChatOpened = ev.opened && ev.type === PanelType.CHAT;
|
||||
this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS;
|
||||
this.isActivitiesOpened = ev.opened && ev.type === PanelType.ACTIVITIES;
|
||||
if (this.isChatOpened) {
|
||||
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() {
|
||||
this.minimalSub = this.libService.minimalObs.subscribe((value: boolean) => {
|
||||
this.isMinimal = value;
|
||||
|
@ -476,6 +554,14 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
this.showParticipantsPanelButton = value;
|
||||
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.showLogo = value;
|
||||
this.cd.markForCheck();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<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-user-settings (onJoinClicked)="_onJoinClicked()" (onCloseClicked)="onLeaveSessionClicked()"></ov-user-settings> -->
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<span>{{ errorMessage }}</span>
|
||||
</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)">
|
||||
<ng-template #toolbar>
|
||||
<ng-container *ngIf="openviduAngularToolbarTemplate">
|
||||
|
@ -68,6 +68,14 @@
|
|||
<ng-container *ngTemplateOutlet="openviduAngularParticipantsPanelTemplate"></ng-container>
|
||||
</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-container *ngTemplateOutlet="openviduAngularAdditionalPanelsTemplate"></ng-container>
|
||||
</ng-template>
|
||||
|
@ -78,6 +86,14 @@
|
|||
<ov-chat-panel id="default-chat-panel"></ov-chat-panel>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #defaultActivitiesPanel>
|
||||
<!-- <ov-activities-panel
|
||||
id="default-activities-panel"
|
||||
(onStartRecordingClicked)="onStartRecordingClicked()"
|
||||
(onStopRecordingClicked)="onStopRecordingClicked()"
|
||||
></ov-activities-panel> -->
|
||||
</ng-template>
|
||||
|
||||
<ng-template #defaultParticipantsPanel>
|
||||
<ov-participants-panel id="default-participants-panel">
|
||||
<ng-template #participantPanelItem let-participant>
|
||||
|
|
|
@ -23,7 +23,8 @@ import {
|
|||
StreamDirective,
|
||||
ToolbarAdditionalButtonsDirective,
|
||||
ToolbarAdditionalPanelButtonsDirective,
|
||||
ToolbarDirective
|
||||
ToolbarDirective,
|
||||
ActivitiesPanelDirective
|
||||
} from '../../directives/template/openvidu-angular.directive';
|
||||
import { ILogger } from '../../models/logger.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 { DeviceService } from '../../services/device/device.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 { StorageService } from '../../services/storage/storage.service';
|
||||
import { TokenService } from '../../services/token/token.service';
|
||||
|
@ -57,6 +58,7 @@ import { TokenService } from '../../services/token/token.service';
|
|||
* | **audioMuted** | `boolean` | {@link AudioMutedDirective} |
|
||||
* | **toolbarScreenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
|
||||
* | **toolbarFullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
||||
* | **toolbarBackgroundEffectsButton** | `boolean` | {@link ToolbarBackgroundEffectsButtonDirective} |
|
||||
* | **toolbarLeaveButton** | `boolean` | {@link ToolbarLeaveButtonDirective} |
|
||||
* | **toolbarChatPanelButton** | `boolean` | {@link ToolbarChatPanelButtonDirective} |
|
||||
* | **toolbarParticipantsPanelButton** | `boolean` | {@link ToolbarParticipantsPanelButtonDirective} |
|
||||
|
@ -135,6 +137,11 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
* @internal
|
||||
*/
|
||||
@ContentChild(ChatPanelDirective) externalChatPanel: ChatPanelDirective;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@ContentChild(ActivitiesPanelDirective) externalActivitiesPanel: ActivitiesPanelDirective;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -174,6 +181,13 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
* @internal
|
||||
*/
|
||||
@ViewChild('defaultParticipantsPanel', { static: false, read: TemplateRef }) defaultParticipantsPanelTemplate: TemplateRef<any>;
|
||||
/**
|
||||
* TODO: WIP
|
||||
* @internal
|
||||
*/
|
||||
@ViewChild('defaultActivitiesPanel', { static: false, read: TemplateRef })
|
||||
defaultActivitiesPanelTemplate: TemplateRef<any>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -195,6 +209,12 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
* @internal
|
||||
*/
|
||||
openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>;
|
||||
/**
|
||||
* TODO: WIP
|
||||
* @internal
|
||||
*/
|
||||
openviduAngularActivitiesPanelTemplate: TemplateRef<any>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -244,14 +264,21 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
this.log.w('Tokens received');
|
||||
this.tokenService.setWebcamToken(tokens.webcam);
|
||||
|
||||
if(tokens.screen) {
|
||||
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) {
|
||||
this.tokenService.setScreenToken(tokens.screen);
|
||||
} else {
|
||||
// Hide screenshare button if screen token does not exist
|
||||
this.libService.screenshareButton.next(false);
|
||||
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
|
||||
*/
|
||||
canPublish: boolean = false;
|
||||
tokensReceived: boolean = false;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -446,6 +473,15 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
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) {
|
||||
this.log.d('Setting EXTERNAL ADDITIONAL PANELS');
|
||||
this.openviduAngularAdditionalPanelsTemplate = this.externalAdditionalPanels.template;
|
||||
|
|
|
@ -13,7 +13,9 @@ import {
|
|||
ToolbarChatPanelButtonDirective,
|
||||
ToolbarDisplaySessionNameDirective,
|
||||
ToolbarDisplayLogoDirective,
|
||||
LogoDirective
|
||||
LogoDirective,
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
ToolbarBackgroundEffectsButtonDirective
|
||||
} from './toolbar.directive';
|
||||
import {
|
||||
AudioMutedDirective,
|
||||
|
@ -32,9 +34,11 @@ import {
|
|||
AudioMutedDirective,
|
||||
ToolbarScreenshareButtonDirective,
|
||||
ToolbarFullscreenButtonDirective,
|
||||
ToolbarBackgroundEffectsButtonDirective,
|
||||
ToolbarLeaveButtonDirective,
|
||||
ToolbarParticipantsPanelButtonDirective,
|
||||
ToolbarChatPanelButtonDirective,
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
ToolbarDisplaySessionNameDirective,
|
||||
ToolbarDisplayLogoDirective,
|
||||
StreamDisplayParticipantNameDirective,
|
||||
|
@ -51,9 +55,11 @@ import {
|
|||
AudioMutedDirective,
|
||||
ToolbarScreenshareButtonDirective,
|
||||
ToolbarFullscreenButtonDirective,
|
||||
ToolbarBackgroundEffectsButtonDirective,
|
||||
ToolbarLeaveButtonDirective,
|
||||
ToolbarParticipantsPanelButtonDirective,
|
||||
ToolbarChatPanelButtonDirective,
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
ToolbarDisplaySessionNameDirective,
|
||||
ToolbarDisplayLogoDirective,
|
||||
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.
|
||||
*
|
||||
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -10,7 +10,9 @@ import {
|
|||
ToolbarAdditionalButtonsDirective,
|
||||
ToolbarDirective,
|
||||
ToolbarAdditionalPanelButtonsDirective,
|
||||
AdditionalPanelsDirective
|
||||
AdditionalPanelsDirective,
|
||||
ActivitiesPanelDirective,
|
||||
BackgroundEffectsPanelDirective
|
||||
} from './openvidu-angular.directive';
|
||||
|
||||
@NgModule({
|
||||
|
@ -25,7 +27,9 @@ import {
|
|||
ToolbarDirective,
|
||||
ToolbarAdditionalButtonsDirective,
|
||||
ToolbarAdditionalPanelButtonsDirective,
|
||||
ParticipantPanelItemElementsDirective
|
||||
ParticipantPanelItemElementsDirective,
|
||||
ActivitiesPanelDirective,
|
||||
BackgroundEffectsPanelDirective
|
||||
],
|
||||
exports: [
|
||||
ChatPanelDirective,
|
||||
|
@ -38,7 +42,9 @@ import {
|
|||
ToolbarDirective,
|
||||
ToolbarAdditionalButtonsDirective,
|
||||
ToolbarAdditionalPanelButtonsDirective,
|
||||
ParticipantPanelItemElementsDirective
|
||||
ParticipantPanelItemElementsDirective,
|
||||
ActivitiesPanelDirective,
|
||||
BackgroundEffectsPanelDirective
|
||||
]
|
||||
})
|
||||
export class OpenViduAngularDirectiveModule {}
|
||||
|
|
|
@ -364,6 +364,29 @@ export class ChatPanelDirective {
|
|||
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.
|
||||
* Here we're going to redefine the participants template in a few code lines.
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export enum PanelType {
|
||||
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 { MatListModule } from '@angular/material/list';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import {MatExpansionModule} from '@angular/material/expansion';
|
||||
|
||||
import { RouterModule } from '@angular/router';
|
||||
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 { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.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({
|
||||
declarations: [
|
||||
|
@ -84,6 +88,9 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
|||
PanelComponent,
|
||||
AvatarProfileComponent,
|
||||
PreJoinComponent,
|
||||
BackgroundEffectsPanelComponent,
|
||||
ActivitiesPanelComponent,
|
||||
RecordingActivityComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
@ -111,6 +118,7 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
|||
MatMenuModule,
|
||||
MatDividerModule,
|
||||
MatListModule,
|
||||
MatExpansionModule,
|
||||
OpenViduAngularDirectiveModule,
|
||||
ApiDirectiveModule
|
||||
],
|
||||
|
@ -137,6 +145,8 @@ import { ApiDirectiveModule } from './directives/api/api.directive.module';
|
|||
PanelComponent,
|
||||
ParticipantsPanelComponent,
|
||||
ParticipantPanelItemComponent,
|
||||
BackgroundEffectsPanelComponent,
|
||||
ActivitiesPanelComponent,
|
||||
ChatPanelComponent,
|
||||
SessionComponent,
|
||||
LayoutComponent,
|
||||
|
|
|
@ -36,6 +36,9 @@ export class OpenViduAngularConfigService {
|
|||
chatPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
chatPanelButtonObs: Observable<boolean>;
|
||||
|
||||
activitiesPanelButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
activitiesPanelButtonObs: Observable<boolean>;
|
||||
|
||||
displaySessionName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
displaySessionNameObs: Observable<boolean>;
|
||||
|
||||
|
@ -49,6 +52,8 @@ export class OpenViduAngularConfigService {
|
|||
settingsButtonObs: Observable<boolean>;
|
||||
participantItemMuteButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
participantItemMuteButtonObs: Observable<boolean>;
|
||||
backgroundEffectsButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
backgroundEffectsButtonObs: Observable<boolean>;
|
||||
|
||||
constructor(@Inject('OPENVIDU_ANGULAR_CONFIG') config: OpenViduAngularConfig) {
|
||||
this.configuration = config;
|
||||
|
@ -62,9 +67,11 @@ export class OpenViduAngularConfigService {
|
|||
//Toolbar observables
|
||||
this.screenshareButtonObs = this.screenshareButton.asObservable();
|
||||
this.fullscreenButtonObs = this.fullscreenButton.asObservable();
|
||||
this.backgroundEffectsButtonObs = this.backgroundEffectsButton.asObservable();
|
||||
this.leaveButtonObs = this.leaveButton.asObservable();
|
||||
this.participantsPanelButtonObs = this.participantsPanelButton.asObservable();
|
||||
this.chatPanelButtonObs = this.chatPanelButton.asObservable();
|
||||
this.activitiesPanelButtonObs = this.activitiesPanelButton.asObservable();
|
||||
this.displaySessionNameObs = this.displaySessionName.asObservable();
|
||||
this.displayLogoObs = this.displayLogo.asObservable();
|
||||
//Stream observables
|
||||
|
@ -82,10 +89,6 @@ export class OpenViduAngularConfigService {
|
|||
return this.configuration?.production;
|
||||
}
|
||||
|
||||
// isWebcomponent(): boolean {
|
||||
// return this.configuration?.webcomponent;
|
||||
// }
|
||||
|
||||
hasParticipantFactory(): boolean {
|
||||
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 { TokenService } from '../token/token.service';
|
||||
|
||||
export enum OpenViduEdition {
|
||||
CE = 'CE',
|
||||
PRO = 'PRO',
|
||||
ENTERPRISE = 'ENTERPRISE'
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OpenViduService {
|
||||
private ovEdition: OpenViduEdition;
|
||||
protected OV: OpenVidu = null;
|
||||
protected OVScreen: OpenVidu = 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
|
||||
*/
|
||||
|
|
|
@ -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/panel/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/participant-panel-item/participant-panel-item.component';
|
||||
export * from './lib/components/session/session.component';
|
||||
|
|
Loading…
Reference in New Issue