mirror of https://github.com/OpenVidu/openvidu.git
ov-components: add toolbar media buttons component
parent
0a49ca91d8
commit
c65b5c8a18
|
@ -0,0 +1,188 @@
|
||||||
|
<!-- Camera button -->
|
||||||
|
@if (showCameraButton) {
|
||||||
|
<button
|
||||||
|
id="camera-btn"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="onCameraToggle()"
|
||||||
|
[disabled]="isConnectionLost || !hasVideoDevices || cameraMuteChanging"
|
||||||
|
[class.disabled]="!isCameraEnabled"
|
||||||
|
[matTooltip]="isCameraEnabled ? ('TOOLBAR.STOP_VIDEO' | translate) : ('TOOLBAR.START_VIDEO' | translate)"
|
||||||
|
[matTooltipDisabled]="!hasVideoDevices"
|
||||||
|
>
|
||||||
|
<mat-icon [id]="isCameraEnabled ? 'videocam' : 'videocam_off'">
|
||||||
|
{{ isCameraEnabled ? 'videocam' : 'videocam_off' }}
|
||||||
|
</mat-icon>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Microphone button -->
|
||||||
|
@if (showMicrophoneButton) {
|
||||||
|
<button
|
||||||
|
id="mic-btn"
|
||||||
|
mat-icon-button
|
||||||
|
(click)="onMicrophoneToggle()"
|
||||||
|
[disabled]="isConnectionLost || !hasAudioDevices || microphoneMuteChanging"
|
||||||
|
[class.disabled]="!isMicrophoneEnabled"
|
||||||
|
[matTooltip]="isMicrophoneEnabled ? ('TOOLBAR.MUTE_AUDIO' | translate) : ('TOOLBAR.UNMUTE_AUDIO' | translate)"
|
||||||
|
[matTooltipDisabled]="!hasAudioDevices"
|
||||||
|
>
|
||||||
|
<mat-icon [id]="isMicrophoneEnabled ? 'mic' : 'mic_off'">
|
||||||
|
{{ isMicrophoneEnabled ? 'mic' : 'mic_off' }}
|
||||||
|
</mat-icon>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Enable Screenshare button -->
|
||||||
|
@if (!isMinimal && showScreenshareButton) {
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
id="screenshare-btn"
|
||||||
|
[matMenuTriggerFor]="isScreenShareEnabled ? screenshareMenu : null"
|
||||||
|
[disabled]="isConnectionLost"
|
||||||
|
[class.active-btn]="isScreenShareEnabled"
|
||||||
|
matTooltip="{{ isScreenShareEnabled ? ('TOOLBAR.DISABLE_SCREEN' | translate) : ('TOOLBAR.ENABLE_SCREEN' | translate) }}"
|
||||||
|
(click)="!isScreenShareEnabled && onScreenShareToggle()"
|
||||||
|
>
|
||||||
|
<mat-icon>screen_share</mat-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Screenshare button menu -->
|
||||||
|
<mat-menu #screenshareMenu="matMenu" id="screenshare-menu">
|
||||||
|
<button mat-menu-item (click)="onScreenTrackReplace()" id="replace-screen-button">
|
||||||
|
<mat-icon>picture_in_picture</mat-icon>
|
||||||
|
<span>{{ 'STREAM.REPLACE_SCREEN' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
<mat-divider class="divider"></mat-divider>
|
||||||
|
<button mat-menu-item (click)="onScreenShareToggle()" id="disable-screen-button">
|
||||||
|
<mat-icon>stop_screen_share</mat-icon>
|
||||||
|
<span>{{ 'TOOLBAR.DISABLE_SCREEN' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
}
|
||||||
|
|
||||||
|
<ng-container *ngIf="toolbarAdditionalButtonsTemplate && additionalButtonsPosition && additionalButtonsPosition === 'beforeMenu'">
|
||||||
|
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- More options button -->
|
||||||
|
@if (!isMinimal && showMoreOptionsButton) {
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
id="more-options-btn"
|
||||||
|
[matMenuTriggerFor]="settingsMenu"
|
||||||
|
[disabled]="isConnectionLost"
|
||||||
|
matTooltip="{{ 'TOOLBAR.MORE_OPTIONS' | translate }}"
|
||||||
|
>
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #settingsMenu="matMenu" id="more-options-menu">
|
||||||
|
<!-- Fullscreen button -->
|
||||||
|
@if (showFullscreenButton) {
|
||||||
|
<button mat-menu-item id="fullscreen-btn" (click)="onFullscreenToggle()">
|
||||||
|
<mat-icon>{{ isFullscreenActive ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
||||||
|
<span>{{ isFullscreenActive ? ('TOOLBAR.EXIT_FULLSCREEN' | translate) : ('TOOLBAR.FULLSCREEN' | translate) }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Recording button -->
|
||||||
|
@if (showRecordingButton) {
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
id="recording-btn"
|
||||||
|
[disabled]="
|
||||||
|
recordingStatus === _recordingStatus.STARTING ||
|
||||||
|
recordingStatus === _recordingStatus.STOPPING ||
|
||||||
|
!hasRoomTracksPublished
|
||||||
|
"
|
||||||
|
[matTooltip]="!hasRoomTracksPublished ? ('TOOLBAR.NO_TRACKS_PUBLISHED' | translate) : ''"
|
||||||
|
(click)="onRecordingToggle()"
|
||||||
|
>
|
||||||
|
<mat-icon color="warn">radio_button_checked</mat-icon>
|
||||||
|
<span>
|
||||||
|
{{
|
||||||
|
recordingStatus === _recordingStatus.STOPPED ||
|
||||||
|
recordingStatus === _recordingStatus.STOPPING ||
|
||||||
|
recordingStatus === _recordingStatus.FAILED
|
||||||
|
? ('TOOLBAR.START_RECORDING' | translate)
|
||||||
|
: ('TOOLBAR.STOP_RECORDING' | translate)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- View recordings button -->
|
||||||
|
@if (showViewRecordingsButton) {
|
||||||
|
<button mat-menu-item id="view-recordings-btn" (click)="onViewRecordingsClick()">
|
||||||
|
<mat-icon>video_library</mat-icon>
|
||||||
|
<span>{{ 'TOOLBAR.VIEW_RECORDINGS' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Broadcasting button -->
|
||||||
|
@if (showBroadcastingButton) {
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
id="toolbar-broadcasting-btn"
|
||||||
|
[disabled]="broadcastingStatus === _broadcastingStatus.STARTING || recordingStatus === _broadcastingStatus.STOPPING"
|
||||||
|
(click)="onBroadcastingToggle()"
|
||||||
|
>
|
||||||
|
<mat-icon>sensors</mat-icon>
|
||||||
|
<span>
|
||||||
|
{{
|
||||||
|
broadcastingStatus === _broadcastingStatus.STOPPED ||
|
||||||
|
broadcastingStatus === _broadcastingStatus.STOPPING ||
|
||||||
|
broadcastingStatus === _broadcastingStatus.FAILED
|
||||||
|
? ('PANEL.STREAMING.START' | translate)
|
||||||
|
: ('PANEL.STREAMING.STOP' | translate)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Virtual background button -->
|
||||||
|
@if (showBackgroundEffectsButton) {
|
||||||
|
<button mat-menu-item id="virtual-bg-btn" [disabled]="!isCameraEnabled" (click)="onBackgroundEffectsToggle()">
|
||||||
|
<mat-icon><span class="material-symbols-outlined">background_replace</span></mat-icon>
|
||||||
|
<span>{{ 'TOOLBAR.BACKGROUND' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Captions button -->
|
||||||
|
<!-- <button
|
||||||
|
*ngIf="!isMinimal && showCaptionsButton"
|
||||||
|
[disabled]="isConnectionLost"
|
||||||
|
mat-menu-item
|
||||||
|
id="captions-btn"
|
||||||
|
(click)="onCaptionsToggle()"
|
||||||
|
>
|
||||||
|
<mat-icon>closed_caption</mat-icon>
|
||||||
|
<span *ngIf="captionsEnabled">{{ 'TOOLBAR.DISABLE_CAPTIONS' | translate }}</span>
|
||||||
|
<span *ngIf="!captionsEnabled">{{ 'TOOLBAR.ENABLE_CAPTIONS' | translate }}</span>
|
||||||
|
</button> -->
|
||||||
|
|
||||||
|
<!-- Divider before settings -->
|
||||||
|
@if (showSettingsButton) {
|
||||||
|
<mat-divider class="divider"></mat-divider>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Settings button -->
|
||||||
|
@if (showSettingsButton) {
|
||||||
|
<button mat-menu-item id="toolbar-settings-btn" (click)="onSettingsToggle()">
|
||||||
|
<mat-icon>settings</mat-icon>
|
||||||
|
<span>{{ 'TOOLBAR.SETTINGS' | translate }}</span>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</mat-menu>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- External additional buttons -->
|
||||||
|
<ng-container *ngIf="toolbarAdditionalButtonsTemplate && additionalButtonsPosition && additionalButtonsPosition === 'afterMenu'">
|
||||||
|
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- Leave session button -->
|
||||||
|
@if (showLeaveButton) {
|
||||||
|
<button mat-icon-button (click)="onLeaveClick()" id="leave-btn" matTooltip="{{ 'TOOLBAR.LEAVE' | translate }}">
|
||||||
|
<mat-icon>call_end</mat-icon>
|
||||||
|
</button>
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.mat-mdc-icon-button {
|
||||||
|
--mat-mdc-button-persistent-ripple-color: transparent !important;
|
||||||
|
--mat-mdc-button-ripple-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: var(--ov-toolbar-buttons-radius);
|
||||||
|
color: var(--ov-secondary-action-color);
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: var(--ov-error-color) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(mat-menu-item),
|
||||||
|
button:not(.mat-mdc-menu-item) ::ng-deep button:not(mat-menu-item),
|
||||||
|
::ng-deep button:not(#screenshare-menu) {
|
||||||
|
background-color: var(--ov-primary-action-color);
|
||||||
|
color: var(--ov-secondary-action-color);
|
||||||
|
margin: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshare-menu {
|
||||||
|
}
|
||||||
|
|
||||||
|
#disable-screen-button > mat-icon {
|
||||||
|
color: var(--ov-error-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-btn,
|
||||||
|
::ng-deep .active-btn {
|
||||||
|
background-color: var(--ov-accent-action-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#leave-btn {
|
||||||
|
background-color: var(--ov-error-color) !important;
|
||||||
|
border-radius: var(--ov-leave-button-radius) !important;
|
||||||
|
width: 65px !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-icon-button[disabled] {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
margin: 8px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blink {
|
||||||
|
animation: blinker 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animation for general blinking */
|
||||||
|
@keyframes blinker {
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-badge-content {
|
||||||
|
background-color: var(--ov-warn-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-mdc-menu-item {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
color: var(--ov-text-surface-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-mdc-menu-item mat-icon {
|
||||||
|
color: var(--ov-text-surface-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep #toolbar-broadcasting-btn > .mat-icon {
|
||||||
|
color: var(--ov-broadcasting-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep #recording-btn > .mat-icon {
|
||||||
|
color: var(--ov-recording-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-mdc-menu-panel {
|
||||||
|
border-radius: var(--ov-surface-radius) !important;
|
||||||
|
background-color: var(--ov-surface-color) !important;
|
||||||
|
box-shadow: var(--ov-border-shadow) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles for XS screens */
|
||||||
|
@media (max-width: 599px) {
|
||||||
|
/* Animation for recording blinking */
|
||||||
|
@keyframes blinker-recording {
|
||||||
|
50% {
|
||||||
|
background-color: var(--ov-recording-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animation for broadcasting blinking */
|
||||||
|
@keyframes blinker-broadcasting {
|
||||||
|
50% {
|
||||||
|
background-color: var(--ov-broadcasting-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply blinking animations to buttons */
|
||||||
|
.blinking-broadcasting-button {
|
||||||
|
animation: blinker-broadcasting 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
.blinking-recording-button {
|
||||||
|
animation: blinker-recording 1.5s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ToolbarMediaButtonsComponent } from './toolbar-media-buttons.component';
|
||||||
|
|
||||||
|
describe('ToolbarMediaButtonsComponent', () => {
|
||||||
|
let component: ToolbarMediaButtonsComponent;
|
||||||
|
let fixture: ComponentFixture<ToolbarMediaButtonsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ToolbarMediaButtonsComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ToolbarMediaButtonsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
|
||||||
|
import { RecordingStatus } from '../../../models/recording.model';
|
||||||
|
import { BroadcastingStatus } from '../../../models/broadcasting.model';
|
||||||
|
import { ToolbarAdditionalButtonsPosition } from '../../../models/toolbar.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ov-toolbar-media-buttons',
|
||||||
|
templateUrl: './toolbar-media-buttons.component.html',
|
||||||
|
styleUrl: './toolbar-media-buttons.component.scss',
|
||||||
|
standalone: false
|
||||||
|
})
|
||||||
|
export class ToolbarMediaButtonsComponent {
|
||||||
|
|
||||||
|
// Camera related inputs
|
||||||
|
@Input() showCameraButton: boolean = true;
|
||||||
|
@Input() isCameraEnabled: boolean = true;
|
||||||
|
@Input() cameraMuteChanging: boolean = false;
|
||||||
|
|
||||||
|
// Microphone related inputs
|
||||||
|
@Input() showMicrophoneButton: boolean = true;
|
||||||
|
@Input() isMicrophoneEnabled: boolean = true;
|
||||||
|
@Input() microphoneMuteChanging: boolean = false;
|
||||||
|
|
||||||
|
// Screenshare related inputs
|
||||||
|
@Input() showScreenshareButton: boolean = true;
|
||||||
|
@Input() isScreenShareEnabled: boolean = false;
|
||||||
|
|
||||||
|
// Device availability inputs
|
||||||
|
@Input() hasVideoDevices: boolean = true;
|
||||||
|
@Input() hasAudioDevices: boolean = true;
|
||||||
|
|
||||||
|
// Connection state inputs
|
||||||
|
@Input() isConnectionLost: boolean = false;
|
||||||
|
|
||||||
|
// UI state inputs
|
||||||
|
@Input() isMinimal: boolean = false;
|
||||||
|
|
||||||
|
// More options menu inputs
|
||||||
|
@Input() showMoreOptionsButton: boolean = true;
|
||||||
|
@Input() showFullscreenButton: boolean = true;
|
||||||
|
@Input() showRecordingButton: boolean = true;
|
||||||
|
@Input() showViewRecordingsButton: boolean = false;
|
||||||
|
@Input() showBroadcastingButton: boolean = true;
|
||||||
|
@Input() showBackgroundEffectsButton: boolean = true;
|
||||||
|
@Input() showCaptionsButton: boolean = true;
|
||||||
|
@Input() showSettingsButton: boolean = true;
|
||||||
|
|
||||||
|
// Fullscreen state
|
||||||
|
@Input() isFullscreenActive: boolean = false;
|
||||||
|
|
||||||
|
// Recording related inputs
|
||||||
|
@Input() recordingStatus: RecordingStatus = RecordingStatus.STOPPED;
|
||||||
|
@Input() hasRoomTracksPublished: boolean = false;
|
||||||
|
|
||||||
|
// Broadcasting related inputs
|
||||||
|
@Input() broadcastingStatus: BroadcastingStatus = BroadcastingStatus.STOPPED;
|
||||||
|
|
||||||
|
// Captions
|
||||||
|
@Input() captionsEnabled: boolean = false;
|
||||||
|
|
||||||
|
// Leave button
|
||||||
|
@Input() showLeaveButton: boolean = true;
|
||||||
|
|
||||||
|
// Additional buttons template
|
||||||
|
@Input() toolbarAdditionalButtonsTemplate: TemplateRef<any> | null = null;
|
||||||
|
@Input() additionalButtonsPosition: ToolbarAdditionalButtonsPosition | undefined;
|
||||||
|
|
||||||
|
// Status enums for template usage
|
||||||
|
_recordingStatus = RecordingStatus;
|
||||||
|
_broadcastingStatus = BroadcastingStatus;
|
||||||
|
|
||||||
|
// Media button outputs
|
||||||
|
@Output() cameraToggled = new EventEmitter<void>();
|
||||||
|
@Output() microphoneToggled = new EventEmitter<void>();
|
||||||
|
@Output() screenShareToggled = new EventEmitter<void>();
|
||||||
|
@Output() screenTrackReplaced = new EventEmitter<void>();
|
||||||
|
|
||||||
|
// More options menu outputs
|
||||||
|
@Output() fullscreenToggled = new EventEmitter<void>();
|
||||||
|
@Output() recordingToggled = new EventEmitter<void>();
|
||||||
|
@Output() viewRecordingsClicked = new EventEmitter<void>();
|
||||||
|
@Output() broadcastingToggled = new EventEmitter<void>();
|
||||||
|
@Output() backgroundEffectsToggled = new EventEmitter<void>();
|
||||||
|
@Output() captionsToggled = new EventEmitter<void>();
|
||||||
|
@Output() settingsToggled = new EventEmitter<void>();
|
||||||
|
|
||||||
|
// Leave button output
|
||||||
|
@Output() leaveClicked = new EventEmitter<void>();
|
||||||
|
|
||||||
|
// Event handler methods
|
||||||
|
onCameraToggle(): void {
|
||||||
|
this.cameraToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMicrophoneToggle(): void {
|
||||||
|
this.microphoneToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onScreenShareToggle(): void {
|
||||||
|
this.screenShareToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onScreenTrackReplace(): void {
|
||||||
|
this.screenTrackReplaced.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFullscreenToggle(): void {
|
||||||
|
this.fullscreenToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onRecordingToggle(): void {
|
||||||
|
this.recordingToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewRecordingsClick(): void {
|
||||||
|
this.viewRecordingsClicked.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onBroadcastingToggle(): void {
|
||||||
|
this.broadcastingToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onBackgroundEffectsToggle(): void {
|
||||||
|
this.backgroundEffectsToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCaptionsToggle(): void {
|
||||||
|
this.captionsToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSettingsToggle(): void {
|
||||||
|
this.settingsToggled.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeaveClick(): void {
|
||||||
|
this.leaveClicked.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -40,203 +40,48 @@
|
||||||
|
|
||||||
<!-- Media and menu buttons container -->
|
<!-- Media and menu buttons container -->
|
||||||
<div class="media-buttons-container" id="media-buttons-container">
|
<div class="media-buttons-container" id="media-buttons-container">
|
||||||
<!-- Camera button -->
|
<ov-toolbar-media-buttons
|
||||||
<button
|
[showCameraButton]="showCameraButton"
|
||||||
id="camera-btn"
|
[isCameraEnabled]="isCameraEnabled"
|
||||||
mat-icon-button
|
[cameraMuteChanging]="cameraMuteChanging"
|
||||||
*ngIf="showCameraButton"
|
[showMicrophoneButton]="showMicrophoneButton"
|
||||||
(click)="toggleCamera()"
|
[isMicrophoneEnabled]="isMicrophoneEnabled"
|
||||||
[disabled]="isConnectionLost || !hasVideoDevices || cameraMuteChanging"
|
[microphoneMuteChanging]="microphoneMuteChanging"
|
||||||
[class.disabled]="!isCameraEnabled"
|
[showScreenshareButton]="showScreenshareButton"
|
||||||
[matTooltip]="isCameraEnabled ? ('TOOLBAR.STOP_VIDEO' | translate) : ('TOOLBAR.START_VIDEO' | translate)"
|
[isScreenShareEnabled]="isScreenShareEnabled"
|
||||||
[matTooltipDisabled]="!hasVideoDevices"
|
[hasVideoDevices]="hasVideoDevices"
|
||||||
>
|
[hasAudioDevices]="hasAudioDevices"
|
||||||
<mat-icon *ngIf="isCameraEnabled" id="videocam"> videocam </mat-icon>
|
[isConnectionLost]="isConnectionLost"
|
||||||
<mat-icon *ngIf="!isCameraEnabled" id="videocam_off"> videocam_off </mat-icon>
|
[isMinimal]="isMinimal"
|
||||||
</button>
|
[showMoreOptionsButton]="showMoreOptionsButton"
|
||||||
|
[showFullscreenButton]="showFullscreenButton"
|
||||||
<!-- Microphone button -->
|
[showRecordingButton]="showRecordingButton"
|
||||||
<button
|
[showViewRecordingsButton]="showViewRecordingsButton"
|
||||||
id="mic-btn"
|
[showBroadcastingButton]="showBroadcastingButton"
|
||||||
mat-icon-button
|
[showBackgroundEffectsButton]="showBackgroundEffectsButton"
|
||||||
*ngIf="showMicrophoneButton"
|
[showCaptionsButton]="showCaptionsButton"
|
||||||
(click)="toggleMicrophone()"
|
[showSettingsButton]="showSettingsButton"
|
||||||
[disabled]="isConnectionLost || !hasAudioDevices || microphoneMuteChanging"
|
[isFullscreenActive]="isFullscreenActive"
|
||||||
[class.disabled]="!isMicrophoneEnabled"
|
[recordingStatus]="recordingStatus"
|
||||||
[matTooltip]="isMicrophoneEnabled ? ('TOOLBAR.MUTE_AUDIO' | translate) : ('TOOLBAR.UNMUTE_AUDIO' | translate)"
|
[hasRoomTracksPublished]="hasRoomTracksPublished"
|
||||||
[matTooltipDisabled]="!hasAudioDevices"
|
[broadcastingStatus]="broadcastingStatus"
|
||||||
>
|
[captionsEnabled]="captionsEnabled"
|
||||||
<mat-icon *ngIf="isMicrophoneEnabled" id="mic"> mic </mat-icon>
|
[showLeaveButton]="showLeaveButton"
|
||||||
<mat-icon *ngIf="!isMicrophoneEnabled" id="mic_off"> mic_off </mat-icon>
|
[toolbarAdditionalButtonsTemplate]="toolbarAdditionalButtonsTemplate"
|
||||||
</button>
|
[additionalButtonsPosition]="additionalButtonsPosition"
|
||||||
|
(cameraToggled)="toggleCamera()"
|
||||||
<!-- Enable Screenshare button -->
|
(microphoneToggled)="toggleMicrophone()"
|
||||||
<button
|
(screenShareToggled)="toggleScreenShare()"
|
||||||
mat-icon-button
|
(screenTrackReplaced)="replaceScreenTrack()"
|
||||||
*ngIf="!isMinimal && showScreenshareButton && !isScreenShareEnabled"
|
(fullscreenToggled)="toggleFullscreen()"
|
||||||
id="screenshare-btn"
|
(recordingToggled)="toggleRecording()"
|
||||||
(click)="toggleScreenShare()"
|
(viewRecordingsClicked)="onViewRecordingsClicked.emit()"
|
||||||
[disabled]="isConnectionLost"
|
(broadcastingToggled)="toggleBroadcasting()"
|
||||||
matTooltip="{{ 'TOOLBAR.ENABLE_SCREEN' | translate }}"
|
(backgroundEffectsToggled)="toggleBackgroundEffects()"
|
||||||
>
|
(captionsToggled)="onCaptionsToggle()"
|
||||||
<mat-icon>screen_share</mat-icon>
|
(settingsToggled)="toggleSettings()"
|
||||||
</button>
|
(leaveClicked)="disconnect()"
|
||||||
<!-- Screenshare button menu -->
|
></ov-toolbar-media-buttons>
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
*ngIf="!isMinimal && showScreenshareButton && isScreenShareEnabled"
|
|
||||||
id="screenshare-btn"
|
|
||||||
[matMenuTriggerFor]="screenshareMenu"
|
|
||||||
[disabled]="isConnectionLost"
|
|
||||||
class="active-btn"
|
|
||||||
matTooltip="{{ 'TOOLBAR.DISABLE_SCREEN' | translate }}"
|
|
||||||
>
|
|
||||||
<mat-icon>screen_share</mat-icon>
|
|
||||||
</button>
|
|
||||||
<mat-menu #screenshareMenu="matMenu" id="screenshare-menu">
|
|
||||||
<button mat-menu-item (click)="replaceScreenTrack()" id="replace-screen-button">
|
|
||||||
<mat-icon>picture_in_picture</mat-icon>
|
|
||||||
<span>{{ 'STREAM.REPLACE_SCREEN' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
<mat-divider class="divider"></mat-divider>
|
|
||||||
<button mat-menu-item (click)="toggleScreenShare()" id="disable-screen-button">
|
|
||||||
<mat-icon>stop_screen_share</mat-icon>
|
|
||||||
<span>{{ 'TOOLBAR.DISABLE_SCREEN' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
</mat-menu>
|
|
||||||
|
|
||||||
<ng-container *ngIf="toolbarAdditionalButtonsTemplate && additionalButtonsPosition && additionalButtonsPosition === 'beforeMenu'">
|
|
||||||
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<!-- More options button -->
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
id="more-options-btn"
|
|
||||||
*ngIf="!isMinimal && showMoreOptionsButton"
|
|
||||||
[matMenuTriggerFor]="settingsMenu"
|
|
||||||
[disabled]="isConnectionLost"
|
|
||||||
matTooltip="{{ 'TOOLBAR.MORE_OPTIONS' | translate }}"
|
|
||||||
>
|
|
||||||
<mat-icon>more_vert</mat-icon>
|
|
||||||
</button>
|
|
||||||
<mat-menu #settingsMenu="matMenu" id="more-options-menu">
|
|
||||||
<!-- Fullscreen button -->
|
|
||||||
<button *ngIf="showFullscreenButton" mat-menu-item id="fullscreen-btn" (click)="toggleFullscreen()">
|
|
||||||
<mat-icon *ngIf="!isFullscreenActive">fullscreen</mat-icon>
|
|
||||||
<span *ngIf="!isFullscreenActive">{{ 'TOOLBAR.FULLSCREEN' | translate }}</span>
|
|
||||||
|
|
||||||
<mat-icon *ngIf="isFullscreenActive">fullscreen_exit</mat-icon>
|
|
||||||
<span *ngIf="isFullscreenActive">{{ 'TOOLBAR.EXIT_FULLSCREEN' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Recording button -->
|
|
||||||
<button
|
|
||||||
*ngIf="!isMinimal && showRecordingButton"
|
|
||||||
mat-menu-item
|
|
||||||
id="recording-btn"
|
|
||||||
[disabled]="
|
|
||||||
recordingStatus === _recordingStatus.STARTING ||
|
|
||||||
recordingStatus === _recordingStatus.STOPPING ||
|
|
||||||
!hasRoomTracksPublished
|
|
||||||
"
|
|
||||||
[matTooltip]="!hasRoomTracksPublished ? ('TOOLBAR.NO_TRACKS_PUBLISHED' | translate) : ''"
|
|
||||||
(click)="toggleRecording()"
|
|
||||||
>
|
|
||||||
<mat-icon color="warn">radio_button_checked</mat-icon>
|
|
||||||
@if (
|
|
||||||
recordingStatus === _recordingStatus.STOPPED ||
|
|
||||||
recordingStatus === _recordingStatus.STOPPING ||
|
|
||||||
recordingStatus === _recordingStatus.FAILED
|
|
||||||
) {
|
|
||||||
<span class="blink">
|
|
||||||
{{ 'TOOLBAR.START_RECORDING' | translate }}
|
|
||||||
</span>
|
|
||||||
} @else if (recordingStatus === _recordingStatus.STARTED || recordingStatus === _recordingStatus.STARTING) {
|
|
||||||
<span>{{ 'TOOLBAR.STOP_RECORDING' | translate }}</span>
|
|
||||||
}
|
|
||||||
</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 -->
|
|
||||||
<button
|
|
||||||
*ngIf="!isMinimal && showBroadcastingButton"
|
|
||||||
mat-menu-item
|
|
||||||
id="toolbar-broadcasting-btn"
|
|
||||||
[disabled]="broadcastingStatus === _broadcastingStatus.STARTING || recordingStatus === _broadcastingStatus.STOPPING"
|
|
||||||
(click)="toggleBroadcasting()"
|
|
||||||
>
|
|
||||||
<mat-icon>sensors</mat-icon>
|
|
||||||
<span
|
|
||||||
*ngIf="
|
|
||||||
broadcastingStatus === _broadcastingStatus.STOPPED ||
|
|
||||||
broadcastingStatus === _broadcastingStatus.STOPPING ||
|
|
||||||
broadcastingStatus === _broadcastingStatus.FAILED
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ 'PANEL.STREAMING.START' | translate }}
|
|
||||||
</span>
|
|
||||||
<span *ngIf="broadcastingStatus === _broadcastingStatus.STARTED || broadcastingStatus === _broadcastingStatus.STARTING">
|
|
||||||
{{ 'PANEL.STREAMING.STOP' | translate }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Virtual background button -->
|
|
||||||
<button
|
|
||||||
*ngIf="!isMinimal && showBackgroundEffectsButton"
|
|
||||||
[disabled]="!isCameraEnabled"
|
|
||||||
mat-menu-item
|
|
||||||
id="virtual-bg-btn"
|
|
||||||
(click)="toggleBackgroundEffects()"
|
|
||||||
>
|
|
||||||
<mat-icon><span class="material-symbols-outlined"> background_replace </span></mat-icon>
|
|
||||||
<span>{{ 'TOOLBAR.BACKGROUND' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Captions button -->
|
|
||||||
<!-- <button
|
|
||||||
*ngIf="!isMinimal && showCaptionsButton"
|
|
||||||
[disabled]="isConnectionLost"
|
|
||||||
mat-menu-item
|
|
||||||
id="captions-btn"
|
|
||||||
(click)="toggleCaptions()"
|
|
||||||
>
|
|
||||||
<mat-icon>closed_caption</mat-icon>
|
|
||||||
<span *ngIf="captionsEnabled">{{ 'TOOLBAR.DISABLE_CAPTIONS' | translate }}</span>
|
|
||||||
<span *ngIf="!captionsEnabled">{{ 'TOOLBAR.ENABLE_CAPTIONS' | translate }}</span>
|
|
||||||
</button> -->
|
|
||||||
|
|
||||||
<mat-divider class="divider" *ngIf="!isMinimal && showSettingsButton"></mat-divider>
|
|
||||||
|
|
||||||
<!-- Settings button -->
|
|
||||||
<button *ngIf="!isMinimal && showSettingsButton" mat-menu-item id="toolbar-settings-btn" (click)="toggleSettings()">
|
|
||||||
<mat-icon>settings</mat-icon>
|
|
||||||
<span>{{ 'TOOLBAR.SETTINGS' | translate }}</span>
|
|
||||||
</button>
|
|
||||||
</mat-menu>
|
|
||||||
|
|
||||||
<!-- External additional buttons -->
|
|
||||||
<ng-container *ngIf="toolbarAdditionalButtonsTemplate && additionalButtonsPosition && additionalButtonsPosition === 'afterMenu'">
|
|
||||||
<ng-container *ngTemplateOutlet="toolbarAdditionalButtonsTemplate"></ng-container>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<!-- Leave session button -->
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
*ngIf="showLeaveButton"
|
|
||||||
(click)="disconnect()"
|
|
||||||
id="leave-btn"
|
|
||||||
matTooltip="{{ 'TOOLBAR.LEAVE' | translate }}"
|
|
||||||
>
|
|
||||||
<mat-icon>call_end</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Panel buttons (chat, participants, activities) -->
|
<!-- Panel buttons (chat, participants, activities) -->
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
// ov-toolbar-media-buttons {
|
||||||
|
// display: flex;
|
||||||
|
// justify-content: center;
|
||||||
|
// align-items: center;
|
||||||
|
// flex: 1;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
.menu-buttons-container {
|
.menu-buttons-container {
|
||||||
flex: 20%;
|
flex: 20%;
|
||||||
|
@ -47,40 +54,9 @@
|
||||||
max-height: 100% !important;
|
max-height: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#media-buttons-container mat-icon {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#media-buttons-container button,
|
|
||||||
#menu-buttons-container button {
|
#menu-buttons-container button {
|
||||||
border-radius: var(--ov-toolbar-buttons-radius);
|
border-radius: var(--ov-toolbar-buttons-radius);
|
||||||
color: var(--ov-secondary-action-color);
|
color: var(--ov-secondary-action-color);
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
background-color: var(--ov-error-color) !important;
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#media-buttons-container > button,
|
|
||||||
::ng-deep #media-buttons-container > button,
|
|
||||||
#media-buttons-container:not(#media-buttons-container > button) button,
|
|
||||||
/* Applying css for external additional buttons*/
|
|
||||||
::ng-deep #media-buttons-container:not(#media-buttons-container > button) button {
|
|
||||||
// width: 40px;
|
|
||||||
// height: 40px;
|
|
||||||
background-color: var(--ov-primary-action-color);
|
|
||||||
color: var(--ov-secondary-action-color);
|
|
||||||
margin: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#disable-screen-button > mat-icon {
|
|
||||||
color: var(--ov-error-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active-btn,
|
|
||||||
::ng-deep .active-btn {
|
|
||||||
background-color: var(--ov-accent-action-color) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#branding-logo {
|
#branding-logo {
|
||||||
|
@ -146,34 +122,11 @@
|
||||||
animation: blinker 1.5s linear infinite;
|
animation: blinker 1.5s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
#leave-btn {
|
|
||||||
background-color: var(--ov-error-color) !important;
|
|
||||||
border-radius: var(--ov-leave-button-radius) !important;
|
|
||||||
width: 65px !important;
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-mdc-icon-button[disabled] {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
::ng-deep .mat-badge-content {
|
::ng-deep .mat-badge-content {
|
||||||
background-color: var(--ov-warn-color);
|
background-color: var(--ov-warn-color);
|
||||||
}
|
}
|
||||||
.divider {
|
|
||||||
margin: 8px 0px;
|
|
||||||
}
|
|
||||||
::ng-deep .mat-mdc-menu-item {
|
|
||||||
/* margin-bottom: 10px; */
|
|
||||||
height: 40px;
|
|
||||||
line-height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animation for general blinking */
|
|
||||||
@keyframes blinker {
|
|
||||||
50% {
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styles for XS screens */
|
/* Styles for XS screens */
|
||||||
@media (max-width: 599px) {
|
@media (max-width: 599px) {
|
||||||
|
|
|
@ -651,7 +651,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
*/
|
*/
|
||||||
// toggleCaptions() {
|
onCaptionsToggle() {
|
||||||
// if (this.openviduService.isOpenViduPro()) {
|
// if (this.openviduService.isOpenViduPro()) {
|
||||||
// this.layoutService.toggleCaptions();
|
// this.layoutService.toggleCaptions();
|
||||||
// } else {
|
// } else {
|
||||||
|
@ -660,7 +660,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
// this.translateService.translate('PANEL.PRO_FEATURE')
|
// this.translateService.translate('PANEL.PRO_FEATURE')
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { ChatPanelComponent } from './components/panel/chat-panel/chat-panel.com
|
||||||
import { SessionComponent } from './components/session/session.component';
|
import { SessionComponent } from './components/session/session.component';
|
||||||
import { StreamComponent } from './components/stream/stream.component';
|
import { StreamComponent } from './components/stream/stream.component';
|
||||||
import { ToolbarComponent } from './components/toolbar/toolbar.component';
|
import { ToolbarComponent } from './components/toolbar/toolbar.component';
|
||||||
|
import { ToolbarMediaButtonsComponent } from './components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component';
|
||||||
import { MediaElementComponent } from './components/media-element/media-element.component';
|
import { MediaElementComponent } from './components/media-element/media-element.component';
|
||||||
|
|
||||||
import { LinkifyPipe } from './pipes/linkify.pipe';
|
import { LinkifyPipe } from './pipes/linkify.pipe';
|
||||||
|
@ -76,7 +77,8 @@ const privateComponents = [
|
||||||
VideoDevicesComponent,
|
VideoDevicesComponent,
|
||||||
AudioDevicesComponent,
|
AudioDevicesComponent,
|
||||||
ParticipantNameInputComponent,
|
ParticipantNameInputComponent,
|
||||||
LangSelectorComponent
|
LangSelectorComponent,
|
||||||
|
ToolbarMediaButtonsComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -15,6 +15,7 @@ export * from './lib/components/panel/participants-panel/participant-panel-item/
|
||||||
export * from './lib/components/panel/participants-panel/participants-panel/participants-panel.component';
|
export * from './lib/components/panel/participants-panel/participants-panel/participants-panel.component';
|
||||||
export * from './lib/components/stream/stream.component';
|
export * from './lib/components/stream/stream.component';
|
||||||
export * from './lib/components/toolbar/toolbar.component';
|
export * from './lib/components/toolbar/toolbar.component';
|
||||||
|
export * from './lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component';
|
||||||
export * from './lib/components/videoconference/videoconference.component';
|
export * from './lib/components/videoconference/videoconference.component';
|
||||||
export * from './lib/config/openvidu-components-angular.config';
|
export * from './lib/config/openvidu-components-angular.config';
|
||||||
// Directives
|
// Directives
|
||||||
|
|
Loading…
Reference in New Issue