mirror of https://github.com/OpenVidu/openvidu.git
ov-components: implement read-only mode and customizable controls for recording activity
parent
98c7e3f751
commit
b659400c88
|
@ -17,6 +17,8 @@
|
||||||
(onRecordingDeleteRequested)="onRecordingDeleteRequested.emit($event)"
|
(onRecordingDeleteRequested)="onRecordingDeleteRequested.emit($event)"
|
||||||
(onRecordingDownloadClicked)="onRecordingDownloadClicked.emit($event)"
|
(onRecordingDownloadClicked)="onRecordingDownloadClicked.emit($event)"
|
||||||
(onRecordingPlayClicked)="onRecordingPlayClicked.emit($event)"
|
(onRecordingPlayClicked)="onRecordingPlayClicked.emit($event)"
|
||||||
|
(onViewRecordingClicked)="onViewRecordingClicked.emit($event)"
|
||||||
|
(onViewRecordingsClicked)="onViewRecordingsClicked.emit()"
|
||||||
></ov-recording-activity>
|
></ov-recording-activity>
|
||||||
<ov-broadcasting-activity
|
<ov-broadcasting-activity
|
||||||
*ngIf="showBroadcastingActivity"
|
*ngIf="showBroadcastingActivity"
|
||||||
|
|
|
@ -54,6 +54,21 @@ export class ActivitiesPanelComponent implements OnInit {
|
||||||
*/
|
*/
|
||||||
@Output() onRecordingPlayClicked: EventEmitter<RecordingPlayClickedEvent> = new EventEmitter<RecordingPlayClickedEvent>();
|
@Output() onRecordingPlayClicked: EventEmitter<RecordingPlayClickedEvent> = new EventEmitter<RecordingPlayClickedEvent>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Provides event notifications that fire when view recordings button has been clicked.
|
||||||
|
* This event is triggered when the user wants to view all recordings in an external page.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingsClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Provides event notifications that fire when view recording button has been clicked.
|
||||||
|
* This event is triggered when the user wants to view a specific recording in an external page.
|
||||||
|
* It provides the recording ID as event data.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides event notifications that fire when start broadcasting button is clicked.
|
* Provides event notifications that fire when start broadcasting button is clicked.
|
||||||
* It provides the {@link BroadcastingStartRequestedEvent} payload as event data.
|
* It provides the {@link BroadcastingStartRequestedEvent} payload as event data.
|
||||||
|
|
|
@ -27,7 +27,10 @@
|
||||||
<mat-icon class="blink" *ngIf="recordingStatus === recStatusEnum.STARTED">radio_button_checked</mat-icon>
|
<mat-icon class="blink" *ngIf="recordingStatus === recStatusEnum.STARTED">radio_button_checked</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
<h3 matListItemTitle class="activity-title">{{ 'PANEL.RECORDING.TITLE' | translate }}</h3>
|
<h3 matListItemTitle class="activity-title">{{ 'PANEL.RECORDING.TITLE' | translate }}</h3>
|
||||||
<p matListItemLine class="activity-subtitle">{{ 'PANEL.RECORDING.SUBTITLE' | translate }}</p>
|
|
||||||
|
<p matListItemLine class="activity-subtitle">
|
||||||
|
{{ isReadOnlyMode ? ('PANEL.RECORDING.VIEW_ONLY_SUBTITLE' | translate) : ('PANEL.RECORDING.SUBTITLE' | translate) }}
|
||||||
|
</p>
|
||||||
<div class="activity-action-buttons" matListItemMeta>
|
<div class="activity-action-buttons" matListItemMeta>
|
||||||
<div
|
<div
|
||||||
id="recording-status"
|
id="recording-status"
|
||||||
|
@ -56,53 +59,85 @@
|
||||||
|
|
||||||
<!-- Empty state content -->
|
<!-- Empty state content -->
|
||||||
<div *ngIf="recordingList.length === 0" class="empty-state">
|
<div *ngIf="recordingList.length === 0" class="empty-state">
|
||||||
<h2 class="recording-title">{{ 'PANEL.RECORDING.CONTENT_TITLE' | translate }}</h2>
|
<h2 class="recording-title">
|
||||||
<span class="recording-subtitle">{{ 'PANEL.RECORDING.CONTENT_SUBTITLE' | translate }}</span>
|
{{
|
||||||
|
isReadOnlyMode
|
||||||
|
? ('PANEL.RECORDING.VIEW_ONLY_CONTENT_TITLE' | translate)
|
||||||
|
: ('PANEL.RECORDING.CONTENT_TITLE' | translate)
|
||||||
|
}}
|
||||||
|
</h2>
|
||||||
|
<span class="recording-subtitle">
|
||||||
|
{{
|
||||||
|
isReadOnlyMode
|
||||||
|
? recordingList.length === 0
|
||||||
|
? ('PANEL.RECORDING.NO_RECORDINGS_AVAILABLE' | translate)
|
||||||
|
: ('PANEL.RECORDING.VIEW_ONLY_CONTENT_SUBTITLE' | translate)
|
||||||
|
: ('PANEL.RECORDING.CONTENT_SUBTITLE' | translate)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Recording control buttons -->
|
<!-- Recording control buttons -->
|
||||||
<div class="item recording-action-buttons">
|
@if (!isReadOnlyMode) {
|
||||||
<!-- Stop recording button -->
|
<div class="item recording-action-buttons">
|
||||||
<button *ngIf="recordingAlive" mat-flat-button id="stop-recording-btn" (click)="stopRecording()">
|
<!-- Stop recording button -->
|
||||||
<span>{{ 'TOOLBAR.STOP_RECORDING' | translate }}</span>
|
<button *ngIf="recordingAlive" mat-flat-button id="stop-recording-btn" (click)="stopRecording()">
|
||||||
</button>
|
<span>{{ 'TOOLBAR.STOP_RECORDING' | translate }}</span>
|
||||||
|
|
||||||
<!-- Start recording button -->
|
|
||||||
<div
|
|
||||||
*ngIf="recordingStatus === recStatusEnum.STOPPED"
|
|
||||||
[matTooltip]="!hasRoomTracksPublished ? ('PANEL.RECORDING.NO_TRACKS_PUBLISHED' | translate) : ''"
|
|
||||||
[matTooltipDisabled]="hasRoomTracksPublished"
|
|
||||||
class="start-recording-button-container"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
[disabled]="!hasRoomTracksPublished"
|
|
||||||
[ngClass]="{ 'disable-recording-btn': !hasRoomTracksPublished }"
|
|
||||||
mat-flat-button
|
|
||||||
id="start-recording-btn"
|
|
||||||
(click)="startRecording()"
|
|
||||||
>
|
|
||||||
<span>{{ 'TOOLBAR.START_RECORDING' | translate }}</span>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Recording status messages -->
|
<!-- Start recording button -->
|
||||||
<div class="recording-status-messages">
|
<div
|
||||||
<span *ngIf="recordingStatus === recStatusEnum.STARTING" class="recording-message">
|
*ngIf="recordingStatus === recStatusEnum.STOPPED"
|
||||||
{{ 'PANEL.RECORDING.STARTING' | translate }}
|
[matTooltip]="!hasRoomTracksPublished ? ('PANEL.RECORDING.NO_TRACKS_PUBLISHED' | translate) : ''"
|
||||||
</span>
|
[matTooltipDisabled]="hasRoomTracksPublished"
|
||||||
|
class="start-recording-button-container"
|
||||||
<span *ngIf="recordingStatus === recStatusEnum.STOPPING" class="recording-message">
|
>
|
||||||
{{ 'PANEL.RECORDING.STOPPING' | translate }}
|
<button
|
||||||
</span>
|
[disabled]="!hasRoomTracksPublished"
|
||||||
|
[ngClass]="{ 'disable-recording-btn': !hasRoomTracksPublished }"
|
||||||
<div *ngIf="recordingStatus === recStatusEnum.FAILED" class="recording-error-container">
|
mat-flat-button
|
||||||
<span class="recording-error">Message: {{ recordingError }}</span>
|
id="start-recording-btn"
|
||||||
<button mat-flat-button id="reset-recording-status-btn" (click)="resetStatus()">
|
(click)="startRecording()"
|
||||||
<span>{{ 'PANEL.RECORDING.ACCEPT' | translate }}</span>
|
>
|
||||||
|
<span>{{ 'TOOLBAR.START_RECORDING' | translate }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- View all recordings button -->
|
||||||
|
<div class="item recording-action-buttons">
|
||||||
|
<button mat-flat-button id="view-recordings-btn" (click)="viewAllRecordings()" class="view-recordings-button">
|
||||||
|
<span>{{ 'TOOLBAR.VIEW_RECORDINGS' | translate }}</span>
|
||||||
|
<mat-icon class="external-link-icon">open_in_new</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recording status messages -->
|
||||||
|
<div class="recording-status-messages">
|
||||||
|
<span *ngIf="recordingStatus === recStatusEnum.STARTING" class="recording-message">
|
||||||
|
{{ 'PANEL.RECORDING.STARTING' | translate }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span *ngIf="recordingStatus === recStatusEnum.STOPPING" class="recording-message">
|
||||||
|
{{ 'PANEL.RECORDING.STOPPING' | translate }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div *ngIf="recordingStatus === recStatusEnum.FAILED" class="recording-error-container">
|
||||||
|
<span class="recording-error">Message: {{ recordingError }}</span>
|
||||||
|
<button mat-flat-button id="reset-recording-status-btn" (click)="resetStatus()">
|
||||||
|
<span>{{ 'PANEL.RECORDING.ACCEPT' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @else {
|
||||||
|
<!-- View all recordings button -->
|
||||||
|
<div class="item recording-action-buttons">
|
||||||
|
<button mat-flat-button id="view-recordings-btn" (click)="viewAllRecordings()" class="view-recordings-button">
|
||||||
|
<span>{{ 'TOOLBAR.VIEW_RECORDINGS' | translate }}</span>
|
||||||
|
<mat-icon class="external-link-icon">open_in_new</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<mat-divider *ngIf="recordingList.length > 0"></mat-divider>
|
<mat-divider *ngIf="recordingList.length > 0"></mat-divider>
|
||||||
|
|
||||||
|
@ -139,37 +174,72 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Recording action buttons -->
|
<!-- Recording action buttons -->
|
||||||
<div *ngIf="recording.status !== recStatusEnum.STARTED" id="recording-action-buttons" class="recording-actions">
|
@if (!isReadOnlyMode) {
|
||||||
<button
|
<div *ngIf="recording.status !== recStatusEnum.STARTED" id="recording-action-buttons" class="recording-actions">
|
||||||
mat-icon-button
|
<button
|
||||||
(click)="play(recording)"
|
*ngIf="showControls.play"
|
||||||
id="play-recording-btn"
|
mat-icon-button
|
||||||
matTooltip="{{ 'PANEL.RECORDING.PLAY' | translate }}"
|
(click)="play(recording)"
|
||||||
class="action-button play-button"
|
id="play-recording-btn"
|
||||||
>
|
matTooltip="{{ 'PANEL.RECORDING.PLAY' | translate }}"
|
||||||
<mat-icon>play_arrow</mat-icon>
|
class="action-button play-button"
|
||||||
</button>
|
>
|
||||||
|
<mat-icon>play_arrow</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
@if (showControls.externalView) {
|
||||||
mat-icon-button
|
<div
|
||||||
(click)="download(recording)"
|
*ngIf="recording.status !== recStatusEnum.STARTED"
|
||||||
id="download-recording-btn"
|
id="recording-action-buttons"
|
||||||
matTooltip="{{ 'PANEL.RECORDING.DOWNLOAD' | translate }}"
|
class="recording-actions"
|
||||||
class="action-button download-button"
|
>
|
||||||
>
|
<button
|
||||||
<mat-icon>download</mat-icon>
|
mat-icon-button
|
||||||
</button>
|
(click)="onViewRecordingClicked.emit(recording.id)"
|
||||||
|
id="watch-recording-btn"
|
||||||
|
matTooltip="{{ 'PANEL.RECORDING.WATCH' | translate }}"
|
||||||
|
class="action-button watch-button"
|
||||||
|
>
|
||||||
|
<mat-icon>open_in_new</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
*ngIf="showControls.download"
|
||||||
(click)="deleteRecording(recording)"
|
mat-icon-button
|
||||||
id="delete-recording-btn"
|
(click)="download(recording)"
|
||||||
matTooltip="{{ 'PANEL.RECORDING.DELETE' | translate }}"
|
id="download-recording-btn"
|
||||||
class="action-button delete-button"
|
matTooltip="{{ 'PANEL.RECORDING.DOWNLOAD' | translate }}"
|
||||||
>
|
class="action-button download-button"
|
||||||
<mat-icon>delete</mat-icon>
|
>
|
||||||
</button>
|
<mat-icon>download</mat-icon>
|
||||||
</div>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
*ngIf="showControls.delete"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="deleteRecording(recording)"
|
||||||
|
id="delete-recording-btn"
|
||||||
|
matTooltip="{{ 'PANEL.RECORDING.DELETE' | translate }}"
|
||||||
|
class="action-button delete-button"
|
||||||
|
>
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<div *ngIf="recording.status !== recStatusEnum.STARTED" id="recording-action-buttons" class="recording-actions">
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
(click)="onViewRecordingClicked.emit(recording.id)"
|
||||||
|
id="watch-recording-btn"
|
||||||
|
matTooltip="{{ 'PANEL.RECORDING.WATCH' | translate }}"
|
||||||
|
class="action-button watch-button"
|
||||||
|
>
|
||||||
|
<mat-icon>open_in_new</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -145,8 +145,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.recording-action-buttons {
|
.recording-action-buttons {
|
||||||
margin-top: 20px;
|
margin: 5px 0px;
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#start-recording-btn {
|
#start-recording-btn {
|
||||||
|
@ -155,6 +154,17 @@
|
||||||
color: var(--ov-secondary-action-color);
|
color: var(--ov-secondary-action-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#view-recordings-btn {
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--ov-accent-action-color);
|
||||||
|
color: var(--ov-secondary-action-color);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.start-recording-button-container {
|
.start-recording-button-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, OnDestroy, Output } from '@angular/core';
|
||||||
import { Subject, takeUntil } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
RecordingDeleteRequestedEvent,
|
RecordingDeleteRequestedEvent,
|
||||||
|
@ -16,6 +16,7 @@ import { RecordingService } from '../../../../services/recording/recording.servi
|
||||||
import { OpenViduService } from '../../../../services/openvidu/openvidu.service';
|
import { OpenViduService } from '../../../../services/openvidu/openvidu.service';
|
||||||
import { ILogger } from '../../../../models/logger.model';
|
import { ILogger } from '../../../../models/logger.model';
|
||||||
import { LoggerService } from '../../../../services/logger/logger.service';
|
import { LoggerService } from '../../../../services/logger/logger.service';
|
||||||
|
import { OpenViduComponentsConfigService } from '../../../../services/config/directive-config.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The **RecordingActivityComponent** is the component that allows showing the recording activity.
|
* The **RecordingActivityComponent** is the component that allows showing the recording activity.
|
||||||
|
@ -31,7 +32,7 @@ import { LoggerService } from '../../../../services/logger/logger.service';
|
||||||
// TODO: Allow to add more than one recording type
|
// TODO: Allow to add more than one recording type
|
||||||
// TODO: Allow to choose where the recording is stored (s3, google cloud, etc)
|
// TODO: Allow to choose where the recording is stored (s3, google cloud, etc)
|
||||||
// TODO: Allow to choose the layout of the recording
|
// TODO: Allow to choose the layout of the recording
|
||||||
export class RecordingActivityComponent implements OnInit {
|
export class RecordingActivityComponent implements OnInit, OnDestroy {
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -67,6 +68,20 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
*/
|
*/
|
||||||
@Output() onRecordingPlayClicked: EventEmitter<RecordingPlayClickedEvent> = new EventEmitter<RecordingPlayClickedEvent>();
|
@Output() onRecordingPlayClicked: EventEmitter<RecordingPlayClickedEvent> = new EventEmitter<RecordingPlayClickedEvent>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Provides event notifications that fire when view recordings button has been clicked.
|
||||||
|
* This event is triggered when the user wants to view all recordings in an external page.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingsClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* This event is fired when the user clicks on the view recording button.
|
||||||
|
* It provides the recording ID as event data.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -108,6 +123,27 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
mouseHovering: boolean = false;
|
mouseHovering: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
isReadOnlyMode: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
viewButtonText: string = 'PANEL.RECORDING.VIEW';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
showControls: { play?: boolean; download?: boolean; delete?: boolean; externalView?: boolean } = {
|
||||||
|
play: true,
|
||||||
|
download: true,
|
||||||
|
delete: true,
|
||||||
|
externalView: false
|
||||||
|
};
|
||||||
|
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
@ -120,7 +156,8 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
private actionService: ActionService,
|
private actionService: ActionService,
|
||||||
private openviduService: OpenViduService,
|
private openviduService: OpenViduService,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
private loggerSrv: LoggerService
|
private loggerSrv: LoggerService,
|
||||||
|
private libService: OpenViduComponentsConfigService
|
||||||
) {
|
) {
|
||||||
this.log = this.loggerSrv.get('RecordingActivityComponent');
|
this.log = this.loggerSrv.get('RecordingActivityComponent');
|
||||||
}
|
}
|
||||||
|
@ -131,6 +168,7 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.subscribeToRecordingStatus();
|
this.subscribeToRecordingStatus();
|
||||||
this.subscribeToTracksChanges();
|
this.subscribeToTracksChanges();
|
||||||
|
this.subscribeToConfigChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -240,6 +278,46 @@ export class RecordingActivityComponent implements OnInit {
|
||||||
this.recordingService.playRecording(recording);
|
this.recordingService.playRecording(recording);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
viewRecording(recording: RecordingInfo) {
|
||||||
|
// This method can be overridden or emit a custom event for navigation
|
||||||
|
// For now, it uses the same behavior as play, but can be customized
|
||||||
|
if (!recording.filename) {
|
||||||
|
this.log.e('Error viewing recording. Recording filename is undefined');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const payload: RecordingPlayClickedEvent = {
|
||||||
|
roomName: this.openviduService.getRoomName(),
|
||||||
|
recordingId: recording.id
|
||||||
|
};
|
||||||
|
this.onRecordingPlayClicked.emit(payload);
|
||||||
|
// You can customize this to navigate to a different page instead
|
||||||
|
this.recordingService.playRecording(recording);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
viewAllRecordings() {
|
||||||
|
this.onViewRecordingsClicked.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private subscribeToConfigChanges() {
|
||||||
|
this.libService.recordingActivityReadOnly$.pipe(takeUntil(this.destroy$)).subscribe((readOnly: boolean) => {
|
||||||
|
this.isReadOnlyMode = readOnly;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.libService.recordingActivityShowControls$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((controls: { play?: boolean; download?: boolean; delete?: boolean; externalView?: boolean }) => {
|
||||||
|
this.showControls = controls;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private subscribeToRecordingStatus() {
|
private subscribeToRecordingStatus() {
|
||||||
this.recordingService.recordingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: RecordingStatusInfo) => {
|
this.recordingService.recordingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: RecordingStatusInfo) => {
|
||||||
const { status, recordingList, error } = event;
|
const { status, recordingList, error } = event;
|
||||||
|
|
|
@ -137,6 +137,14 @@
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- View recordings button -->
|
||||||
|
@if (!isMinimal && showViewRecordingsButton) {
|
||||||
|
<button mat-menu-item id="view-recordings-btn" (click)="onViewRecordingsClicked.emit()">
|
||||||
|
<mat-icon>video_library</mat-icon>
|
||||||
|
<span>{{ 'TOOLBAR.VIEW_RECORDINGS' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
<!-- Broadcasting button -->
|
<!-- Broadcasting button -->
|
||||||
<button
|
<button
|
||||||
*ngIf="!isMinimal && showBroadcastingButton"
|
*ngIf="!isMinimal && showBroadcastingButton"
|
||||||
|
|
|
@ -145,6 +145,12 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
@Output() onBroadcastingStopRequested: EventEmitter<BroadcastingStopRequestedEvent> =
|
@Output() onBroadcastingStopRequested: EventEmitter<BroadcastingStopRequestedEvent> =
|
||||||
new EventEmitter<BroadcastingStopRequestedEvent>();
|
new EventEmitter<BroadcastingStopRequestedEvent>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* This event is fired when the user clicks on the view recordings button.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingsClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -240,6 +246,11 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
showRecordingButton: boolean = true;
|
showRecordingButton: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
showViewRecordingsButton: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -312,6 +323,11 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
isRecordingReadOnlyMode: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
|
@ -602,17 +618,19 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToFullscreenChanged() {
|
private subscribeToFullscreenChanged() {
|
||||||
fromEvent(document, 'fullscreenchange').pipe(takeUntil(this.destroy$)).subscribe(() => {
|
fromEvent(document, 'fullscreenchange')
|
||||||
const isFullscreen = Boolean(document.fullscreenElement);
|
.pipe(takeUntil(this.destroy$))
|
||||||
if (isFullscreen) {
|
.subscribe(() => {
|
||||||
this.cdkOverlayService.setSelector('#session-container');
|
const isFullscreen = Boolean(document.fullscreenElement);
|
||||||
} else {
|
if (isFullscreen) {
|
||||||
this.cdkOverlayService.setSelector('body');
|
this.cdkOverlayService.setSelector('#session-container');
|
||||||
}
|
} else {
|
||||||
this.isFullscreenActive = isFullscreen;
|
this.cdkOverlayService.setSelector('body');
|
||||||
this.onFullscreenEnabledChanged.emit(this.isFullscreenActive);
|
}
|
||||||
this.cd.detectChanges();
|
this.isFullscreenActive = isFullscreen;
|
||||||
});
|
this.onFullscreenEnabledChanged.emit(this.isFullscreenActive);
|
||||||
|
this.cd.detectChanges();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToMenuToggling() {
|
private subscribeToMenuToggling() {
|
||||||
|
@ -661,6 +679,11 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToRecordingStatus() {
|
private subscribeToRecordingStatus() {
|
||||||
|
this.libService.recordingActivityReadOnly$.pipe(takeUntil(this.destroy$)).subscribe((readOnly: boolean) => {
|
||||||
|
this.isRecordingReadOnlyMode = readOnly;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
this.recordingService.recordingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: RecordingStatusInfo) => {
|
this.recordingService.recordingStatusObs.pipe(takeUntil(this.destroy$)).subscribe((event: RecordingStatusInfo) => {
|
||||||
const { status, startedAt } = event;
|
const { status, startedAt } = event;
|
||||||
this.recordingStatus = status;
|
this.recordingStatus = status;
|
||||||
|
@ -696,6 +719,11 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.brandingLogo = value;
|
this.brandingLogo = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
this.libService.toolbarViewRecordingsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
|
this.showViewRecordingsButton = value;
|
||||||
|
this.checkDisplayMoreOptions();
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
this.libService.cameraButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
this.libService.cameraButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
this.showCameraButton = value;
|
this.showCameraButton = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
|
@ -766,8 +794,9 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.libService.toolbarAdditionalButtonsPosition$.pipe(takeUntil(this.destroy$)).subscribe(
|
this.libService.toolbarAdditionalButtonsPosition$
|
||||||
(value: ToolbarAdditionalButtonsPosition) => {
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((value: ToolbarAdditionalButtonsPosition) => {
|
||||||
// Using Promise.resolve() to defer change detection until the next microtask.
|
// Using Promise.resolve() to defer change detection until the next microtask.
|
||||||
// This ensures that Angular's change detection has the latest value before updating the view.
|
// This ensures that Angular's change detection has the latest value before updating the view.
|
||||||
// Without this, Angular's OnPush strategy might not immediately reflect the change,
|
// Without this, Angular's OnPush strategy might not immediately reflect the change,
|
||||||
|
@ -777,8 +806,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.additionalButtonsPosition = value;
|
this.additionalButtonsPosition = value;
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToCaptionsToggling() {
|
private subscribeToCaptionsToggling() {
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
(onRecordingStartRequested)="onRecordingStartRequested.emit($event)"
|
(onRecordingStartRequested)="onRecordingStartRequested.emit($event)"
|
||||||
(onRecordingStopRequested)="onRecordingStopRequested.emit($event)"
|
(onRecordingStopRequested)="onRecordingStopRequested.emit($event)"
|
||||||
(onBroadcastingStopRequested)="onBroadcastingStopRequested.emit($event)"
|
(onBroadcastingStopRequested)="onBroadcastingStopRequested.emit($event)"
|
||||||
|
(onViewRecordingsClicked)="onViewRecordingsClicked.emit()"
|
||||||
>
|
>
|
||||||
<ng-template #toolbarAdditionalButtons>
|
<ng-template #toolbarAdditionalButtons>
|
||||||
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container>
|
<ng-container *ngTemplateOutlet="openviduAngularToolbarAdditionalButtonsTemplate"></ng-container>
|
||||||
|
@ -133,6 +134,8 @@
|
||||||
(onRecordingDeleteRequested)="onRecordingDeleteRequested.emit($event)"
|
(onRecordingDeleteRequested)="onRecordingDeleteRequested.emit($event)"
|
||||||
(onRecordingDownloadClicked)="onRecordingDownloadClicked.emit($event)"
|
(onRecordingDownloadClicked)="onRecordingDownloadClicked.emit($event)"
|
||||||
(onRecordingPlayClicked)="onRecordingPlayClicked.emit($event)"
|
(onRecordingPlayClicked)="onRecordingPlayClicked.emit($event)"
|
||||||
|
(onViewRecordingClicked)="onViewRecordingClicked.emit($event)"
|
||||||
|
(onViewRecordingsClicked)="onViewRecordingsClicked.emit()"
|
||||||
(onBroadcastingStartRequested)="onBroadcastingStartRequested.emit($event)"
|
(onBroadcastingStartRequested)="onBroadcastingStartRequested.emit($event)"
|
||||||
(onBroadcastingStopRequested)="onBroadcastingStopRequested.emit($event)"
|
(onBroadcastingStopRequested)="onBroadcastingStopRequested.emit($event)"
|
||||||
></ov-activities-panel>
|
></ov-activities-panel>
|
||||||
|
|
|
@ -326,6 +326,13 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
@Output() onRecordingPlayClicked: EventEmitter<RecordingPlayClickedEvent> = new EventEmitter<RecordingPlayClickedEvent>();
|
@Output() onRecordingPlayClicked: EventEmitter<RecordingPlayClickedEvent> = new EventEmitter<RecordingPlayClickedEvent>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* This event is fired when the user clicks on the view recording button.
|
||||||
|
* It provides the recording ID as event data.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingClicked: EventEmitter<string> = new EventEmitter<string>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides event notifications that fire when download recording button is clicked from {@link ActivitiesPanelComponent}.
|
* Provides event notifications that fire when download recording button is clicked from {@link ActivitiesPanelComponent}.
|
||||||
* It provides the {@link RecordingDownloadClickedEvent} payload as event data.
|
* It provides the {@link RecordingDownloadClickedEvent} payload as event data.
|
||||||
|
@ -346,6 +353,12 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
@Output() onBroadcastingStopRequested: EventEmitter<BroadcastingStopRequestedEvent> =
|
@Output() onBroadcastingStopRequested: EventEmitter<BroadcastingStopRequestedEvent> =
|
||||||
new EventEmitter<BroadcastingStopRequestedEvent>();
|
new EventEmitter<BroadcastingStopRequestedEvent>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* This event is fired when the user clicks on the view recordings button.
|
||||||
|
*/
|
||||||
|
@Output() onViewRecordingsClicked: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides event notifications that fire when Room is created for the local participant.
|
* Provides event notifications that fire when Room is created for the local participant.
|
||||||
* It provides the {@link https://openvidu.io/latest/docs/getting-started/#room Room} payload as event data.
|
* It provides the {@link https://openvidu.io/latest/docs/getting-started/#room Room} payload as event data.
|
||||||
|
@ -620,91 +633,80 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToVideconferenceDirectives() {
|
private subscribeToVideconferenceDirectives() {
|
||||||
this.libService.token$
|
this.libService.token$.pipe(skip(1), takeUntil(this.destroy$)).subscribe((token: string) => {
|
||||||
.pipe(
|
try {
|
||||||
skip(1),
|
if (!token) {
|
||||||
takeUntil(this.destroy$)
|
this.log.e('Token is empty');
|
||||||
)
|
return;
|
||||||
.subscribe((token: string) => {
|
|
||||||
try {
|
|
||||||
if (!token) {
|
|
||||||
this.log.e('Token is empty');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const livekitUrl = this.libService.getLivekitUrl();
|
|
||||||
this.openviduService.initializeAndSetToken(token, livekitUrl);
|
|
||||||
this.log.d('Token has been successfully set. Room is ready to join');
|
|
||||||
this.isRoomReady = true;
|
|
||||||
this.showPrejoin = false;
|
|
||||||
} catch (error) {
|
|
||||||
this.log.e('Error trying to set token', error);
|
|
||||||
this._tokenError = error;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.libService.tokenError$
|
const livekitUrl = this.libService.getLivekitUrl();
|
||||||
.pipe(takeUntil(this.destroy$))
|
this.openviduService.initializeAndSetToken(token, livekitUrl);
|
||||||
.subscribe((error: any) => {
|
this.log.d('Token has been successfully set. Room is ready to join');
|
||||||
if (!error) return;
|
this.isRoomReady = true;
|
||||||
|
this.showPrejoin = false;
|
||||||
this.log.e('Token error received', error);
|
} catch (error) {
|
||||||
|
this.log.e('Error trying to set token', error);
|
||||||
this._tokenError = error;
|
this._tokenError = error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!this.showPrejoin) {
|
this.libService.tokenError$.pipe(takeUntil(this.destroy$)).subscribe((error: any) => {
|
||||||
this.actionService.openDialog(error.name, error.message, false);
|
if (!error) return;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.libService.prejoin$
|
this.log.e('Token error received', error);
|
||||||
.pipe(takeUntil(this.destroy$))
|
this._tokenError = error;
|
||||||
.subscribe((value: boolean) => {
|
|
||||||
this.showPrejoin = value;
|
|
||||||
if (!this.showPrejoin) {
|
|
||||||
// Emit token ready if the prejoin page won't be shown
|
|
||||||
|
|
||||||
// Ensure we have a participant name before proceeding with the join
|
if (!this.showPrejoin) {
|
||||||
this.log.d('Prejoin page is hidden, checking participant name');
|
this.actionService.openDialog(error.name, error.message, false);
|
||||||
// Check if we have a participant name already
|
}
|
||||||
if (this.latestParticipantName) {
|
});
|
||||||
// We have a name, proceed immediately
|
|
||||||
this._onReadyToJoin();
|
this.libService.prejoin$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => {
|
||||||
} else {
|
this.showPrejoin = value;
|
||||||
// No name yet - set up a one-time subscription to wait for it
|
if (!this.showPrejoin) {
|
||||||
this.libService.participantName$
|
// Emit token ready if the prejoin page won't be shown
|
||||||
.pipe(
|
|
||||||
filter((name) => !!name),
|
// Ensure we have a participant name before proceeding with the join
|
||||||
take(1),
|
this.log.d('Prejoin page is hidden, checking participant name');
|
||||||
takeUntil(this.destroy$)
|
// Check if we have a participant name already
|
||||||
)
|
if (this.latestParticipantName) {
|
||||||
.subscribe(() => {
|
// We have a name, proceed immediately
|
||||||
// Now we have the name in latestParticipantName
|
this._onReadyToJoin();
|
||||||
this._onReadyToJoin();
|
} else {
|
||||||
});
|
// No name yet - set up a one-time subscription to wait for it
|
||||||
// Add safety timeout in case name never arrives
|
this.libService.participantName$
|
||||||
setTimeout(() => {
|
.pipe(
|
||||||
if (!this.latestParticipantName) {
|
filter((name) => !!name),
|
||||||
this.log.w('No participant name received after timeout, proceeding anyway');
|
take(1),
|
||||||
const storedName = this.storageSrv.getParticipantName();
|
takeUntil(this.destroy$)
|
||||||
if (storedName) {
|
)
|
||||||
this.latestParticipantName = storedName;
|
.subscribe(() => {
|
||||||
this.libService.setParticipantName(storedName);
|
// Now we have the name in latestParticipantName
|
||||||
}
|
this._onReadyToJoin();
|
||||||
this._onReadyToJoin();
|
});
|
||||||
|
// Add safety timeout in case name never arrives
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.latestParticipantName) {
|
||||||
|
this.log.w('No participant name received after timeout, proceeding anyway');
|
||||||
|
const storedName = this.storageSrv.getParticipantName();
|
||||||
|
if (storedName) {
|
||||||
|
this.latestParticipantName = storedName;
|
||||||
|
this.libService.setParticipantName(storedName);
|
||||||
}
|
}
|
||||||
}, 1000);
|
this._onReadyToJoin();
|
||||||
}
|
}
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
// this.cd.markForCheck();
|
}
|
||||||
});
|
// this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
this.libService.participantName$
|
this.libService.participantName$.pipe(takeUntil(this.destroy$)).subscribe((name: string) => {
|
||||||
.pipe(takeUntil(this.destroy$))
|
if (name) {
|
||||||
.subscribe((name: string) => {
|
this.latestParticipantName = name;
|
||||||
if (name) {
|
this.storageSrv.setParticipantName(name);
|
||||||
this.latestParticipantName = name;
|
}
|
||||||
this.storageSrv.setParticipantName(name);
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,10 @@ import {
|
||||||
FallbackLogoDirective,
|
FallbackLogoDirective,
|
||||||
LayoutRemoteParticipantsDirective,
|
LayoutRemoteParticipantsDirective,
|
||||||
PrejoinDisplayParticipantName,
|
PrejoinDisplayParticipantName,
|
||||||
ToolbarBrandingLogoDirective
|
ToolbarBrandingLogoDirective,
|
||||||
|
ToolbarViewRecordingsButtonDirective,
|
||||||
|
RecordingActivityReadOnlyDirective,
|
||||||
|
RecordingActivityShowControlsDirective
|
||||||
} from './internals.directive';
|
} from './internals.directive';
|
||||||
import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive';
|
import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive';
|
||||||
import {
|
import {
|
||||||
|
@ -65,6 +68,8 @@ const directives = [
|
||||||
PrejoinDirective,
|
PrejoinDirective,
|
||||||
PrejoinDisplayParticipantName,
|
PrejoinDisplayParticipantName,
|
||||||
VideoEnabledDirective,
|
VideoEnabledDirective,
|
||||||
|
RecordingActivityReadOnlyDirective,
|
||||||
|
RecordingActivityShowControlsDirective,
|
||||||
AudioEnabledDirective,
|
AudioEnabledDirective,
|
||||||
ShowDisconnectionDialogDirective,
|
ShowDisconnectionDialogDirective,
|
||||||
RecordingStreamBaseUrlDirective,
|
RecordingStreamBaseUrlDirective,
|
||||||
|
@ -84,6 +89,7 @@ const directives = [
|
||||||
ToolbarDisplayLogoDirective,
|
ToolbarDisplayLogoDirective,
|
||||||
ToolbarSettingsButtonDirective,
|
ToolbarSettingsButtonDirective,
|
||||||
ToolbarAdditionalButtonsPossitionDirective,
|
ToolbarAdditionalButtonsPossitionDirective,
|
||||||
|
ToolbarViewRecordingsButtonDirective,
|
||||||
StreamDisplayParticipantNameDirective,
|
StreamDisplayParticipantNameDirective,
|
||||||
StreamDisplayAudioDetectionDirective,
|
StreamDisplayAudioDetectionDirective,
|
||||||
StreamVideoControlsDirective,
|
StreamVideoControlsDirective,
|
||||||
|
|
|
@ -161,3 +161,181 @@ export class PrejoinDisplayParticipantName implements OnDestroy {
|
||||||
this.libService.setPrejoinDisplayParticipantName(value);
|
this.libService.setPrejoinDisplayParticipantName(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* The **recordingActivityReadOnly** directive sets the recording activity panel to read-only mode.
|
||||||
|
* In this mode, users can only view recordings without the ability to start, stop, or delete them.
|
||||||
|
*
|
||||||
|
* It is only available for {@link VideoconferenceComponent}.
|
||||||
|
*
|
||||||
|
* Default: `false`
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* <ov-videoconference [recordingActivityReadOnly]="true"></ov-videoconference>
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'ov-videoconference[recordingActivityReadOnly]',
|
||||||
|
standalone: false
|
||||||
|
})
|
||||||
|
export class RecordingActivityReadOnlyDirective implements OnDestroy {
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set recordingActivityReadOnly(value: boolean) {
|
||||||
|
this.update(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
public elementRef: ElementRef,
|
||||||
|
private libService: OpenViduComponentsConfigService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.update(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
update(value: boolean) {
|
||||||
|
this.libService.setRecordingActivityReadOnly(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* The **recordingActivityShowControls** directive allows to show/hide specific recording controls (play, download, delete, externalView).
|
||||||
|
* You can pass an object with boolean properties to control which buttons are shown.
|
||||||
|
*
|
||||||
|
* It is only available for {@link VideoconferenceComponent}.
|
||||||
|
*
|
||||||
|
* Default: `{ play: true, download: true, delete: true, externalView: false }`
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* <ov-videoconference [recordingActivityShowControls]="{ play: false, download: true, delete: false }"></ov-videoconference>
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'ov-videoconference[recordingActivityShowControls]',
|
||||||
|
standalone: false
|
||||||
|
})
|
||||||
|
export class RecordingActivityShowControlsDirective implements OnDestroy {
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set recordingActivityShowControls(value: { play?: boolean; download?: boolean; delete?: boolean; externalView?: boolean }) {
|
||||||
|
this.update(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
public elementRef: ElementRef,
|
||||||
|
private libService: OpenViduComponentsConfigService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.update({ play: true, download: true, delete: true, externalView: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
update(value: { play?: boolean; download?: boolean; delete?: boolean; externalView?: boolean }) {
|
||||||
|
this.libService.setRecordingActivityShowControls(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* The **viewRecordingsButton** directive allows show/hide the view recordings toolbar button.
|
||||||
|
*
|
||||||
|
* Default: `false`
|
||||||
|
*
|
||||||
|
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component:
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* <ov-videoconference [toolbarViewRecordingsButton]="true"></ov-videoconference>
|
||||||
|
*
|
||||||
|
* \
|
||||||
|
* And it also can be used in the {@link ToolbarComponent}.
|
||||||
|
* @example
|
||||||
|
* <ov-toolbar [viewRecordingsButton]="true"></ov-toolbar>
|
||||||
|
*
|
||||||
|
* When the button is clicked, it will fire the `onViewRecordingsClicked` event.
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: 'ov-videoconference[toolbarViewRecordingsButton], ov-toolbar[viewRecordingsButton]',
|
||||||
|
standalone: false
|
||||||
|
})
|
||||||
|
export class ToolbarViewRecordingsButtonDirective implements AfterViewInit, OnDestroy {
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set toolbarViewRecordingsButton(value: boolean) {
|
||||||
|
this.viewRecordingsValue = value;
|
||||||
|
this.update(this.viewRecordingsValue);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
@Input() set viewRecordingsButton(value: boolean) {
|
||||||
|
this.viewRecordingsValue = value;
|
||||||
|
this.update(this.viewRecordingsValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private viewRecordingsValue: boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
public elementRef: ElementRef,
|
||||||
|
private libService: OpenViduComponentsConfigService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this.update(this.viewRecordingsValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
private clear() {
|
||||||
|
this.viewRecordingsValue = false;
|
||||||
|
this.update(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(value: boolean) {
|
||||||
|
if (this.libService.getToolbarViewRecordingsButton() !== value) {
|
||||||
|
this.libService.setToolbarViewRecordingsButton(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "参与者",
|
"PARTICIPANTS": "参与者",
|
||||||
"CHAT": "聊天",
|
"CHAT": "聊天",
|
||||||
"ACTIVITIES": "活动",
|
"ACTIVITIES": "活动",
|
||||||
"NO_TRACKS_PUBLISHED": "请分享音频或视频以开始录制。"
|
"NO_TRACKS_PUBLISHED": "请分享音频或视频以开始录制。",
|
||||||
|
"VIEW_RECORDINGS": "查看录像"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "设置",
|
"SETTINGS": "设置",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "为后人记录你的会议",
|
"SUBTITLE": "为后人记录你的会议",
|
||||||
"CONTENT_TITLE": "记录你的视频通话",
|
"CONTENT_TITLE": "记录你的视频通话",
|
||||||
"CONTENT_SUBTITLE": "当录音完成后,你将可以轻松地下载它",
|
"CONTENT_SUBTITLE": "当录音完成后,你将可以轻松地下载它",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "查看和访问房间录音",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "视频通话录音",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "在这里您可以访问所有可用的录音",
|
||||||
|
"WATCH": "观看",
|
||||||
"STARTING": "开始录音",
|
"STARTING": "开始录音",
|
||||||
"STOPPING": "停止录制",
|
"STOPPING": "停止录制",
|
||||||
"IN_PROGRESS": "录音中",
|
"IN_PROGRESS": "录音中",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "下载",
|
"DOWNLOAD": "下载",
|
||||||
"RECORDINGS": "录制",
|
"RECORDINGS": "录制",
|
||||||
"NO_MODERATOR": "只有主持人可以开始录音",
|
"NO_MODERATOR": "只有主持人可以开始录音",
|
||||||
"NO_TRACKS_PUBLISHED": "请分享音频或视频以开始录制。"
|
"NO_TRACKS_PUBLISHED": "请分享音频或视频以开始录制。",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "目前没有可用的录音"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "直播",
|
"TITLE": "直播",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "Participants",
|
"PARTICIPANTS": "Participants",
|
||||||
"CHAT": "Chat",
|
"CHAT": "Chat",
|
||||||
"ACTIVITIES": "Activities",
|
"ACTIVITIES": "Activities",
|
||||||
"NO_TRACKS_PUBLISHED": "Share audio or video to start recording."
|
"NO_TRACKS_PUBLISHED": "Share audio or video to start recording.",
|
||||||
|
"VIEW_RECORDINGS": "View recordings"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "Settings",
|
"SETTINGS": "Settings",
|
||||||
|
@ -115,6 +116,13 @@
|
||||||
"SUBTITLE": "Record your meeting for posterity",
|
"SUBTITLE": "Record your meeting for posterity",
|
||||||
"CONTENT_TITLE": "Record your video call",
|
"CONTENT_TITLE": "Record your video call",
|
||||||
"CONTENT_SUBTITLE": "When recording has finished you will be able to download it with ease",
|
"CONTENT_SUBTITLE": "When recording has finished you will be able to download it with ease",
|
||||||
|
"VIEW_ONLY_TITLE": "Available recordings",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "View and access room recordings",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "Video call recordings",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "Here you can access all available recordings",
|
||||||
|
"VIEW": "View",
|
||||||
|
"WATCH": "Watch",
|
||||||
|
"ACCESS": "Access",
|
||||||
"STARTING": "Starting recording",
|
"STARTING": "Starting recording",
|
||||||
"STOPPING": "Stopping recording",
|
"STOPPING": "Stopping recording",
|
||||||
"IN_PROGRESS": "Recording in progress ...",
|
"IN_PROGRESS": "Recording in progress ...",
|
||||||
|
@ -126,7 +134,9 @@
|
||||||
"DOWNLOAD": "Download",
|
"DOWNLOAD": "Download",
|
||||||
"RECORDINGS": "RECORDINGS",
|
"RECORDINGS": "RECORDINGS",
|
||||||
"NO_MODERATOR": "Only the MODERATOR can start the recording",
|
"NO_MODERATOR": "Only the MODERATOR can start the recording",
|
||||||
"NO_TRACKS_PUBLISHED": "Share audio or video to start recording."
|
"NO_TRACKS_PUBLISHED": "Share audio or video to start recording.",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "No recordings available at this time",
|
||||||
|
"BROWSE_RECORDINGS": "Browse saved recordings"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "Streaming",
|
"TITLE": "Streaming",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "Participantes",
|
"PARTICIPANTS": "Participantes",
|
||||||
"CHAT": "Chat",
|
"CHAT": "Chat",
|
||||||
"ACTIVITIES": "Actividades",
|
"ACTIVITIES": "Actividades",
|
||||||
"NO_TRACKS_PUBLISHED": "Comparte audio o video para poder empezar a grabar."
|
"NO_TRACKS_PUBLISHED": "Comparte audio o video para poder empezar a grabar.",
|
||||||
|
"VIEW_RECORDINGS": "Ver grabaciones"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "Ajustes",
|
"SETTINGS": "Ajustes",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "Graba tus llamadas para la posteridad",
|
"SUBTITLE": "Graba tus llamadas para la posteridad",
|
||||||
"CONTENT_TITLE": "Graba tu video conferencia",
|
"CONTENT_TITLE": "Graba tu video conferencia",
|
||||||
"CONTENT_SUBTITLE": "Cuando la grabación haya finalizado, podrás descargarla con facilidad",
|
"CONTENT_SUBTITLE": "Cuando la grabación haya finalizado, podrás descargarla con facilidad",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "Visualiza y accede a las grabaciones de la sala",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "Grabaciones de la video conferencia",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "Aquí puedes acceder a todas las grabaciones disponibles",
|
||||||
|
"WATCH": "Visualizar",
|
||||||
"STARTING": "Iniciando grabación...",
|
"STARTING": "Iniciando grabación...",
|
||||||
"STOPPING": "Parando grabación",
|
"STOPPING": "Parando grabación",
|
||||||
"IN_PROGRESS": "Grabación en curso",
|
"IN_PROGRESS": "Grabación en curso",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "Descargar",
|
"DOWNLOAD": "Descargar",
|
||||||
"RECORDINGS": "GRABACIONES",
|
"RECORDINGS": "GRABACIONES",
|
||||||
"NO_MODERATOR": "Sólo el MODERADOR puede iniciar la grabación",
|
"NO_MODERATOR": "Sólo el MODERADOR puede iniciar la grabación",
|
||||||
"NO_TRACKS_PUBLISHED": "Comparte audio o video para poder empezar a grabar."
|
"NO_TRACKS_PUBLISHED": "Comparte audio o video para poder empezar a grabar.",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "No hay grabaciones disponibles en este momento"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "Streaming",
|
"TITLE": "Streaming",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "Participants",
|
"PARTICIPANTS": "Participants",
|
||||||
"CHAT": "Chat",
|
"CHAT": "Chat",
|
||||||
"ACTIVITES": "Activités",
|
"ACTIVITES": "Activités",
|
||||||
"NO_TRACKS_PUBLISHED": "Partagez de l’audio ou de la vidéo pour commencer l’enregistrement."
|
"NO_TRACKS_PUBLISHED": "Partagez de l’audio ou de la vidéo pour commencer l’enregistrement.",
|
||||||
|
"VIEW_RECORDINGS": "Voir les enregistrements"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "Paramètres",
|
"SETTINGS": "Paramètres",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "Enregistrez votre réunion pour la postérité",
|
"SUBTITLE": "Enregistrez votre réunion pour la postérité",
|
||||||
"CONTENT_TITLE": "Enregistrez votre appel vidéo",
|
"CONTENT_TITLE": "Enregistrez votre appel vidéo",
|
||||||
"CONTENT_SUBTITLE": "Une fois l'enregistrement terminé, vous pourrez le télécharger facilement",
|
"CONTENT_SUBTITLE": "Une fois l'enregistrement terminé, vous pourrez le télécharger facilement",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "Visualisez et accédez aux enregistrements de la salle",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "Enregistrements d'appel vidéo",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "Ici vous pouvez accéder à tous les enregistrements disponibles",
|
||||||
|
"WATCH": "Regarder",
|
||||||
"STARTING": "Début de l'enregistrement",
|
"STARTING": "Début de l'enregistrement",
|
||||||
"STOPPING": "Arrêt de l'enregistrement",
|
"STOPPING": "Arrêt de l'enregistrement",
|
||||||
"IN_PROGRESS": "Enregistrement en cours",
|
"IN_PROGRESS": "Enregistrement en cours",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "Télécharger",
|
"DOWNLOAD": "Télécharger",
|
||||||
"RECORDINGS": "ENREGISTREMENTS",
|
"RECORDINGS": "ENREGISTREMENTS",
|
||||||
"NO_MODERATOR": "Seul le MODERATEUR peut lancer l'enregistrement",
|
"NO_MODERATOR": "Seul le MODERATEUR peut lancer l'enregistrement",
|
||||||
"NO_TRACKS_PUBLISHED": "Partagez de l’audio ou de la vidéo pour commencer l’enregistrement."
|
"NO_TRACKS_PUBLISHED": "Partagez de l’audio ou de la vidéo pour commencer l’enregistrement.",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "Aucun enregistrement disponible pour le moment"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "Streaming",
|
"TITLE": "Streaming",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "सदस्य",
|
"PARTICIPANTS": "सदस्य",
|
||||||
"CHAT": "बातचीत",
|
"CHAT": "बातचीत",
|
||||||
"ACTIVITIES": "गतिविधियाँ",
|
"ACTIVITIES": "गतिविधियाँ",
|
||||||
"NO_TRACKS_PUBLISHED": "रिकॉर्डिंग शुरू करने के लिए ऑडियो या वीडियो साझा करें।"
|
"NO_TRACKS_PUBLISHED": "रिकॉर्डिंग शुरू करने के लिए ऑडियो या वीडियो साझा करें।",
|
||||||
|
"VIEW_RECORDINGS": "रिकॉर्डिंग देखें"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "सेटिंग्स",
|
"SETTINGS": "सेटिंग्स",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "अपनी बैठक को भावी पीढ़ी के लिए रिकॉर्ड करें",
|
"SUBTITLE": "अपनी बैठक को भावी पीढ़ी के लिए रिकॉर्ड करें",
|
||||||
"CONTENT_TITLE": "अपना वीडियो कॉल रिकॉर्ड करें",
|
"CONTENT_TITLE": "अपना वीडियो कॉल रिकॉर्ड करें",
|
||||||
"CONTENT_SUBTITLE": "रिकॉर्डिंग समाप्त हो जाने पर आप इसे आसानी से डाउनलोड कर सकेंगे",
|
"CONTENT_SUBTITLE": "रिकॉर्डिंग समाप्त हो जाने पर आप इसे आसानी से डाउनलोड कर सकेंगे",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "कमरे की रिकॉर्डिंग देखें और एक्सेस करें",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "वीडियो कॉल रिकॉर्डिंग",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "यहाँ आप सभी उपलब्ध रिकॉर्डिंग तक पहुँच सकते हैं",
|
||||||
|
"WATCH": "देखना",
|
||||||
"STARTING": "रिकॉर्डिंग शुरू कर रहा है",
|
"STARTING": "रिकॉर्डिंग शुरू कर रहा है",
|
||||||
"STOPPING": "रिकॉर्डिंग बंद करना",
|
"STOPPING": "रिकॉर्डिंग बंद करना",
|
||||||
"IN_PROGRESS": "रिकॉर्डिंग चल रही है",
|
"IN_PROGRESS": "रिकॉर्डिंग चल रही है",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "डाउनलोड",
|
"DOWNLOAD": "डाउनलोड",
|
||||||
"RECORDINGS": "रिकॉर्डिंग",
|
"RECORDINGS": "रिकॉर्डिंग",
|
||||||
"NO_MODERATOR": "केवल मॉडरेटर ही रिकॉर्डिंग शुरू कर सकता है",
|
"NO_MODERATOR": "केवल मॉडरेटर ही रिकॉर्डिंग शुरू कर सकता है",
|
||||||
"NO_TRACKS_PUBLISHED": "रिकॉर्डिंग शुरू करने के लिए ऑडियो या वीडियो साझा करें।"
|
"NO_TRACKS_PUBLISHED": "रिकॉर्डिंग शुरू करने के लिए ऑडियो या वीडियो साझा करें।",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "इस समय कोई रिकॉर्डिंग उपलब्ध नहीं है"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "स्ट्रीमिंग",
|
"TITLE": "स्ट्रीमिंग",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "Partecipanti",
|
"PARTICIPANTS": "Partecipanti",
|
||||||
"CHAT": "Chat",
|
"CHAT": "Chat",
|
||||||
"ACTIVITIES": "Attività",
|
"ACTIVITIES": "Attività",
|
||||||
"NO_TRACKS_PUBLISHED": "Condividi audio o video per iniziare la registrazione."
|
"NO_TRACKS_PUBLISHED": "Condividi audio o video per iniziare la registrazione.",
|
||||||
|
"VIEW_RECORDINGS": "Visualizza registrazioni"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "Impostazioni",
|
"SETTINGS": "Impostazioni",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "Registra la tua riunione per i posteri",
|
"SUBTITLE": "Registra la tua riunione per i posteri",
|
||||||
"CONTENT_TITLE": "Registra la tua videochiamata",
|
"CONTENT_TITLE": "Registra la tua videochiamata",
|
||||||
"CONTENT_SUBTITLE": "Al termine della registrazione potrete scaricarla con facilità",
|
"CONTENT_SUBTITLE": "Al termine della registrazione potrete scaricarla con facilità",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "Visualizza e accedi alle registrazioni della sala",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "Registrazioni di videochiamate",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "Qui puoi accedere a tutte le registrazioni disponibili",
|
||||||
|
"WATCH": "Guardare",
|
||||||
"STARTING": "Avvio della registrazione",
|
"STARTING": "Avvio della registrazione",
|
||||||
"STOPPING": "Interruzione della registrazione",
|
"STOPPING": "Interruzione della registrazione",
|
||||||
"IN_PROGRESS": "Registrazione in corso",
|
"IN_PROGRESS": "Registrazione in corso",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "Scarica",
|
"DOWNLOAD": "Scarica",
|
||||||
"RECORDINGS": "REGISTRAZIONI",
|
"RECORDINGS": "REGISTRAZIONI",
|
||||||
"NO_MODERATOR": "Solo il MODERATORE può avviare la registrazione",
|
"NO_MODERATOR": "Solo il MODERATORE può avviare la registrazione",
|
||||||
"NO_TRACKS_PUBLISHED": "Condividi audio o video per iniziare la registrazione."
|
"NO_TRACKS_PUBLISHED": "Condividi audio o video per iniziare la registrazione.",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "Nessuna registrazione disponibile al momento"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "Streaming",
|
"TITLE": "Streaming",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "参加者",
|
"PARTICIPANTS": "参加者",
|
||||||
"CHAT": "チャット",
|
"CHAT": "チャット",
|
||||||
"ACTIVITIES": "アクティビティ",
|
"ACTIVITIES": "アクティビティ",
|
||||||
"NO_TRACKS_PUBLISHED": "録音を開始するには、音声または動画を共有してください。"
|
"NO_TRACKS_PUBLISHED": "録音を開始するには、音声または動画を共有してください。",
|
||||||
|
"VIEW_RECORDINGS": "録画を表示"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "設定",
|
"SETTINGS": "設定",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "会議を録画して保存する",
|
"SUBTITLE": "会議を録画して保存する",
|
||||||
"CONTENT_TITLE": "ビデオ通話を録音する",
|
"CONTENT_TITLE": "ビデオ通話を録音する",
|
||||||
"CONTENT_SUBTITLE": "録画が完了したら、簡単にダウンロードできます",
|
"CONTENT_SUBTITLE": "録画が完了したら、簡単にダウンロードできます",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "ルームの録画を表示してアクセスする",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "ビデオ通話の録画",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "ここで利用可能なすべての録画にアクセスできます",
|
||||||
|
"WATCH": "視聴する",
|
||||||
"STARTING": "録画開始",
|
"STARTING": "録画開始",
|
||||||
"STOPPING": "録音停止",
|
"STOPPING": "録音停止",
|
||||||
"IN_PROGRESS": "録画中",
|
"IN_PROGRESS": "録画中",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "保存",
|
"DOWNLOAD": "保存",
|
||||||
"RECORDINGS": "録画",
|
"RECORDINGS": "録画",
|
||||||
"NO_MODERATOR": "録画を開始できるのは、モデレーターのみです",
|
"NO_MODERATOR": "録画を開始できるのは、モデレーターのみです",
|
||||||
"NO_TRACKS_PUBLISHED": "録音を開始するには、音声または動画を共有してください。"
|
"NO_TRACKS_PUBLISHED": "録音を開始するには、音声または動画を共有してください。",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "現在利用可能な録画はありません"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "ストリーミング",
|
"TITLE": "ストリーミング",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "Deelnemers",
|
"PARTICIPANTS": "Deelnemers",
|
||||||
"CHAT": "Chat",
|
"CHAT": "Chat",
|
||||||
"ACTIVITIES": "Activiteiten",
|
"ACTIVITIES": "Activiteiten",
|
||||||
"NO_TRACKS_PUBLISHED": "Deel audio of video om met opnemen te beginnen."
|
"NO_TRACKS_PUBLISHED": "Deel audio of video om met opnemen te beginnen.",
|
||||||
|
"VIEW_RECORDINGS": "Opnames bekijken"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "Instellingen",
|
"SETTINGS": "Instellingen",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "Neem uw vergadering op voor het nageslacht",
|
"SUBTITLE": "Neem uw vergadering op voor het nageslacht",
|
||||||
"CONTENT_TITLE": "Neem uw videogesprek op",
|
"CONTENT_TITLE": "Neem uw videogesprek op",
|
||||||
"CONTENT_SUBTITLE": "Als de opname klaar is kunt u deze met gemak downloaden",
|
"CONTENT_SUBTITLE": "Als de opname klaar is kunt u deze met gemak downloaden",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "Bekijk en toegang tot kameropnames",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "Videogesprek opnames",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "Hier heeft u toegang tot alle beschikbare opnames",
|
||||||
|
"WATCH": "Bekijken",
|
||||||
"STARTING": "Beginnen met opnemen",
|
"STARTING": "Beginnen met opnemen",
|
||||||
"STOPPING": "Opname stoppen",
|
"STOPPING": "Opname stoppen",
|
||||||
"IN_PROGRESS": "Opname in uitvoering",
|
"IN_PROGRESS": "Opname in uitvoering",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "Downloaden",
|
"DOWNLOAD": "Downloaden",
|
||||||
"RECORDINGS": "OPNAME",
|
"RECORDINGS": "OPNAME",
|
||||||
"NO_MODERATOR": "Alleen de MOEDERATOR kan de opname starten",
|
"NO_MODERATOR": "Alleen de MOEDERATOR kan de opname starten",
|
||||||
"NO_TRACKS_PUBLISHED": "Deel audio of video om met opnemen te beginnen."
|
"NO_TRACKS_PUBLISHED": "Deel audio of video om met opnemen te beginnen.",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "Momenteel zijn er geen opnames beschikbaar"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "Streaming",
|
"TITLE": "Streaming",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"PARTICIPANTS": "Participantes",
|
"PARTICIPANTS": "Participantes",
|
||||||
"CHAT": "Chat",
|
"CHAT": "Chat",
|
||||||
"ACTIVITIES": "Actividades",
|
"ACTIVITIES": "Actividades",
|
||||||
"NO_TRACKS_PUBLISHED": "Compartilhe áudio ou vídeo para começar a gravar."
|
"NO_TRACKS_PUBLISHED": "Compartilhe áudio ou vídeo para começar a gravar.",
|
||||||
|
"VIEW_RECORDINGS": "Ver gravações"
|
||||||
},
|
},
|
||||||
"STREAM": {
|
"STREAM": {
|
||||||
"SETTINGS": "Configurações",
|
"SETTINGS": "Configurações",
|
||||||
|
@ -115,6 +116,10 @@
|
||||||
"SUBTITLE": "Grave a sua reunião para a posteridade",
|
"SUBTITLE": "Grave a sua reunião para a posteridade",
|
||||||
"CONTENT_TITLE": "Grave a sua videochamada",
|
"CONTENT_TITLE": "Grave a sua videochamada",
|
||||||
"CONTENT_SUBTITLE": "Quando a gravação tiver terminado, poderá descarregá-la com facilidade",
|
"CONTENT_SUBTITLE": "Quando a gravação tiver terminado, poderá descarregá-la com facilidade",
|
||||||
|
"VIEW_ONLY_SUBTITLE": "Visualize e acesse gravações da sala",
|
||||||
|
"VIEW_ONLY_CONTENT_TITLE": "Gravações de videochamada",
|
||||||
|
"VIEW_ONLY_CONTENT_SUBTITLE": "Aqui você pode acessar todas as gravações disponíveis",
|
||||||
|
"WATCH": "Assistir",
|
||||||
"STARTING": "Começar a gravação",
|
"STARTING": "Começar a gravação",
|
||||||
"STOPPING": "Parando a gravação",
|
"STOPPING": "Parando a gravação",
|
||||||
"IN_PROGRESS": "Gravação em andamento",
|
"IN_PROGRESS": "Gravação em andamento",
|
||||||
|
@ -126,7 +131,8 @@
|
||||||
"DOWNLOAD": "Download",
|
"DOWNLOAD": "Download",
|
||||||
"RECORDINGS": "GRAVAÇÕES",
|
"RECORDINGS": "GRAVAÇÕES",
|
||||||
"NO_MODERATOR": "Só o MODERADOR pode iniciar a gravação",
|
"NO_MODERATOR": "Só o MODERADOR pode iniciar a gravação",
|
||||||
"NO_TRACKS_PUBLISHED": "Compartilhe áudio ou vídeo para começar a gravar."
|
"NO_TRACKS_PUBLISHED": "Compartilhe áudio ou vídeo para começar a gravar.",
|
||||||
|
"NO_RECORDINGS_AVAILABLE": "Nenhuma gravação disponível no momento"
|
||||||
},
|
},
|
||||||
"STREAMING": {
|
"STREAMING": {
|
||||||
"TITLE": "Streaming",
|
"TITLE": "Streaming",
|
||||||
|
|
|
@ -96,6 +96,8 @@ export class OpenViduComponentsConfigService {
|
||||||
backgroundEffectsButton$: Observable<boolean>;
|
backgroundEffectsButton$: Observable<boolean>;
|
||||||
private recordingButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
private recordingButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
recordingButton$: Observable<boolean>;
|
recordingButton$: Observable<boolean>;
|
||||||
|
private toolbarViewRecordingsButton = <BehaviorSubject<boolean>>new BehaviorSubject(false);
|
||||||
|
toolbarViewRecordingsButton$: Observable<boolean>;
|
||||||
private broadcastingButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
private broadcastingButton = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
broadcastingButton$: Observable<boolean>;
|
broadcastingButton$: Observable<boolean>;
|
||||||
private recordingActivity = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
private recordingActivity = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
|
@ -103,6 +105,14 @@ export class OpenViduComponentsConfigService {
|
||||||
private broadcastingActivity = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
private broadcastingActivity = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||||
broadcastingActivity$: Observable<boolean>;
|
broadcastingActivity$: Observable<boolean>;
|
||||||
|
|
||||||
|
// Recording activity configuration
|
||||||
|
private recordingActivityReadOnly = <BehaviorSubject<boolean>>new BehaviorSubject(false);
|
||||||
|
recordingActivityReadOnly$: Observable<boolean>;
|
||||||
|
private recordingActivityShowControls = <BehaviorSubject<{ play?: boolean; download?: boolean; delete?: boolean }>>(
|
||||||
|
new BehaviorSubject({ play: true, download: true, delete: true })
|
||||||
|
);
|
||||||
|
recordingActivityShowControls$: Observable<{ play?: boolean; download?: boolean; delete?: boolean; externalView?: boolean }>;
|
||||||
|
|
||||||
// Admin
|
// Admin
|
||||||
private adminRecordingsList: BehaviorSubject<RecordingInfo[]> = new BehaviorSubject(<RecordingInfo[]>[]);
|
private adminRecordingsList: BehaviorSubject<RecordingInfo[]> = new BehaviorSubject(<RecordingInfo[]>[]);
|
||||||
adminRecordingsList$: Observable<RecordingInfo[]>;
|
adminRecordingsList$: Observable<RecordingInfo[]>;
|
||||||
|
@ -142,6 +152,7 @@ export class OpenViduComponentsConfigService {
|
||||||
this.displayLogo$ = this.displayLogo.asObservable();
|
this.displayLogo$ = this.displayLogo.asObservable();
|
||||||
this.brandingLogo$ = this.brandingLogo.asObservable();
|
this.brandingLogo$ = this.brandingLogo.asObservable();
|
||||||
this.recordingButton$ = this.recordingButton.asObservable();
|
this.recordingButton$ = this.recordingButton.asObservable();
|
||||||
|
this.toolbarViewRecordingsButton$ = this.toolbarViewRecordingsButton.asObservable();
|
||||||
this.broadcastingButton$ = this.broadcastingButton.asObservable();
|
this.broadcastingButton$ = this.broadcastingButton.asObservable();
|
||||||
this.toolbarSettingsButton$ = this.toolbarSettingsButton.asObservable();
|
this.toolbarSettingsButton$ = this.toolbarSettingsButton.asObservable();
|
||||||
this.captionsButton$ = this.captionsButton.asObservable();
|
this.captionsButton$ = this.captionsButton.asObservable();
|
||||||
|
@ -154,6 +165,8 @@ export class OpenViduComponentsConfigService {
|
||||||
this.participantItemMuteButton$ = this.participantItemMuteButton.asObservable();
|
this.participantItemMuteButton$ = this.participantItemMuteButton.asObservable();
|
||||||
// Recording activity observables
|
// Recording activity observables
|
||||||
this.recordingActivity$ = this.recordingActivity.asObservable();
|
this.recordingActivity$ = this.recordingActivity.asObservable();
|
||||||
|
this.recordingActivityReadOnly$ = this.recordingActivityReadOnly.asObservable();
|
||||||
|
this.recordingActivityShowControls$ = this.recordingActivityShowControls.asObservable();
|
||||||
// Broadcasting activity
|
// Broadcasting activity
|
||||||
this.broadcastingActivity$ = this.broadcastingActivity.asObservable();
|
this.broadcastingActivity$ = this.broadcastingActivity.asObservable();
|
||||||
// Admin dashboard
|
// Admin dashboard
|
||||||
|
@ -357,6 +370,18 @@ export class OpenViduComponentsConfigService {
|
||||||
return this.recordingButton.getValue();
|
return this.recordingButton.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setToolbarViewRecordingsButton(toolbarViewRecordingsButton: boolean) {
|
||||||
|
this.toolbarViewRecordingsButton.next(toolbarViewRecordingsButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
getToolbarViewRecordingsButton(): boolean {
|
||||||
|
return this.toolbarViewRecordingsButton.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
showToolbarViewRecordingsButton(): boolean {
|
||||||
|
return this.getToolbarViewRecordingsButton();
|
||||||
|
}
|
||||||
|
|
||||||
setBroadcastingButton(broadcastingButton: boolean) {
|
setBroadcastingButton(broadcastingButton: boolean) {
|
||||||
this.broadcastingButton.next(broadcastingButton);
|
this.broadcastingButton.next(broadcastingButton);
|
||||||
}
|
}
|
||||||
|
@ -468,4 +493,22 @@ export class OpenViduComponentsConfigService {
|
||||||
setLayoutRemoteParticipants(participants: ParticipantModel[] | undefined) {
|
setLayoutRemoteParticipants(participants: ParticipantModel[] | undefined) {
|
||||||
this.layoutRemoteParticipants.next(participants);
|
this.layoutRemoteParticipants.next(participants);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recording Activity Configuration
|
||||||
|
setRecordingActivityReadOnly(readOnly: boolean) {
|
||||||
|
this.recordingActivityReadOnly.next(readOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
isRecordingActivityReadOnly(): boolean {
|
||||||
|
return this.recordingActivityReadOnly.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setRecordingActivityShowControls(controls: { play?: boolean; download?: boolean; delete?: boolean }) {
|
||||||
|
this.recordingActivityShowControls.next(controls);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRecordingActivityShowControls(): { play?: boolean; download?: boolean; delete?: boolean } {
|
||||||
|
return this.recordingActivityShowControls.getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue